&S[i+2] &S[i]-S S[4*i+4] *(S+i-2) short * int short short AS+2*i+4 (AS+2*i-As)/2=i M[AS+2*(4*i+4)] M[AS+2*(i-2)] leal 4(íx, ìx, 2), êx movl ìx, êx movw 8(íx, ìx, 8), %ax movw -4(íx, ìx, 2), %ax
22.参考答案:
根据汇编指令功能可以推断最终在EAX中返回的值为:
M[a+28*i+4*j]+M[b+20*j+4*i],因为数组a和b都是int型,每个数组元素占4B,因此,M=5, N=7。 23.参考答案:
执行第11行指令后,a[i][j][k]的地址为a+4*(63*i+9*j+k),所以,可以推断出M=9,N=63/9=7。根据第12行指令,可知数组a的大小为4536字节,故L=4536/(4*L*M)=18。 24.参考答案:
(1)常数M=76/4=19,存放在EDI中,变量j存放在ECX中。 (2)上述优化汇编代码对应的函数trans_matrix的C代码如下: 1 void trans_matrix(int a[M][M]) { 2 int i, j, t, *p; 3 int c=(M<<2);
3 for (i = 0; i < M; i++) { 4 p=&a[0][i];
5 for (j = 0; j < M; j++) { 6 t=*p;
7 *p = a[i][j]; 8 a[i][j] = t; 9 p += c; 10 } 11 } 12 }
25.参考答案:
(1)node所需存储空间需要4+(4+4)+4=16字节。成员p、、和next的偏移地址分别为0、4、8和12。 (2)np_init中缺失的表达式如下:
void np_init(struct node *np) {
np-> = np-> ;
np->p = &(np-> ; np->next= np ; }
26.参考答案: 表达式EXPR uptr-> uptr-> &uptr-> uptr-> uptr->[uptr->] TYPE类型 int short short * short * short 汇编指令序列 movl (êx), êx movl êx, (íx) movw 4(êx), %ax movw %ax, (íx) leal 6(êx), êx movw êx, (íx) movl êx, (íx) movl 4(êx), ìx movl (êx, ìx, 2), êx *uptr-> char movl êx, (íx) movl 8(êx), êx movb (êx), %al movb %al, (íx)
27.参考答案:
(1)S1: s c i d
0 2 4 8 总共12字节,按4字节边界对齐 (2)S2: i s c d
0 4 6 7 总共8字节,按4字节边界对齐 (3)S3: c s i d
0 2 4 8 总共12字节,按4字节边界对齐 (4)S4: s c
0 6 总共8字节,按2字节边界对齐 (5)S5: c s i d e
0 4 8 12 16 总共24字节,按4字节边界对齐(Linux下double型按4字节对齐) (6)S6: c s d
0 36 40 总共44字节,按4字节边界对齐 28.参考答案:
Windows平台要求不同的基本类型按照其数据长度进行对齐。每个成员的偏移量如下: c d i s p l g v 0 8 16 20 24 28 32 40
结构总大小为48字节,因为其中的d和g必须是按8字节边界对齐,所以,必须在末尾再加上4个字节,即44+4=48字节。变量长度按照从大到小顺序排列,可以使得结构所占空间最小,因此调整顺序后的结构定义如下: struct {
double d;
long long g; int i;
char *p;
long l; void *v;
short s; char c;
} test;
d g i p l v s c
0 8 16 20 24 28 32 34 结构总大小为34+6=40字节。 29.参考答案:
(1)执行第7行和第10行指令后栈中的信息存放情况如下图所示。其中gets函数的入口参数为buf数组首
地址,应等于getline函数的栈帧底部指针EBP的内容减0x14,而getline函数的栈帧底部指针EBP的内容应等于执行完getline中第2行指令(push ?p)后ESP的内容,此时,R[esp]= =0xbffc07f0-4=0xbffc07ec,故buf数组首地址为R[ebp]-0x14= R[esp]-0x14=0xbffc07ec-0x14=0xbffc07d8。
EBP
08 04 85 c8 返回P的地址 bf fc 08 00 EBP在P中旧值 00 00 00 08 00 00 00 10 00 00 00 05 被调用者保
存寄存器在P中的旧值 buf[7]~ buf[4] buf[3]~ buf[0]
EBP
08 41 39 38 返回P的地址
37 36 35 34 EBP在P中旧值 被调用者保46 45 44 43 存寄存器在42 41 39 38 P中的旧值 37 36 35 34 buf[7]~ 33 32 31 30 buf[4]buf[3]~ buf[0] 33 32 31 30 ESP
a) 执行第7行后的栈
ESP
bf fc 07 d8 gets入口参数
b) 执行第10行后的栈
(2)当执行到getline的ret指令时,假如程序不发生段错误,则正确的返回地址应该是0x80485c8,发
生段错误是因为执行getline的ret指令时得到的返回地址为0x8413938,这个地址所在存储段可能是不可执行的数据段,因而发生了段错误(segmentation fault)。
(3)执行完第10行汇编指令后,被调用者保存寄存器EBX、ESI和EDI在P中的内容已被破坏,同时还破
坏了EBP在P中的内容。
(4)getline的C代码中malloc函数的参数应该为strlen(buf)+1,此外,应该检查malloc函数的返回值
是否为NULL。
30.参考答案:
x86-64过程调用时参数传递是通过通用寄存器进行的,前三个参数所用寄存器顺序为RDI、RSI、RDX。 abc的4种合理的函数原型为:
① viod abc(int c, long *a, int *b);
② viod abc(unsigned c, long *a, int *b); ③ viod abc(long c, long *a, int *b);
④ viod abc(unsigned long c, long *a, int *b);
根据第3、4行指令可知,参数b肯定指向一个32位带符号整数类型;根据第5行指令可知,参数a指向
64位带符号整数类型;而参数c可以是32位,也可以是64位,因为*b为32位,所以取RDI中的低32位R[edi](截断为32位),再和*b相加。同时,参数c可以是带符号整数类型,也可以是无符号整数类型,因为第2行加法指令addl的执行结果对于带符号整数和无符号整数都一样。 31.参考答案:
(1)汇编指令注释如下:
1 movl 8(?p), íx 3: 6 movl íi, êx 3 3
13 movl %esi, êx next->n1. ptr ) – uptr->n2. data2 ;
34.参考答案:
(1)函数trace的入口参数tptr通过RDI寄存器传递。 (2)函数trace完整的C语言代码如下:
long trace( tree_ptr tptr) {
long ret_val=0; tree_ptr p=tptr; while (p!=0) {
ret_val=p->val; p=p->left; }
return ret_val; }
(3)函数trace的功能是:返回二叉树中最左边叶子节点中的值val。