习 题
3. 参考答案:
(1)后缀:w, 源:基址+比例变址+偏移, 目:寄存器 (2)后缀:b, 源:寄存器, 目:基址+偏移 (3)后缀:l, 源:比例变址, 目:寄存器 (4)后缀:b, 源:基址, 目:寄存器 (5)后缀:l, 源:立即数, 目:栈 (6)后缀:l, 源:立即数, 目:寄存器 (7)后缀:w, 源:寄存器, 目:寄存器 (8)后缀:l, 源:基址+变址+偏移, 目:寄存器 4.参考答案:
(1)源操作数是立即数0xFF,需在前面加‘$’
(2)源操作数是16位,而长度后缀是字节‘b’,不一致 (3)目的操作数不能是立即数寻址
(4)操作数位数超过16位,而长度后缀为16位的‘w’ (5)不能用8位寄存器作为目的操作数地址所在寄存器 (6)源操作数寄存器与目操作数寄存器长度不一致 (7)不存在ESX寄存器
(8)源操作数地址中缺少变址寄存器 5.参考答案:
表 题5用表 src_type char int int short unsigned char char int dst_type int char unsigned int unsigned unsigned int 机器级表示 movsbl %al, (íx) movb %al, (íx) movl êx, (íx) movswl %ax, (íx) movzbl %al, (íx) movsbl %al, (íx) movl êx, (íx) 6.参考答案:
(1)xptr、yptr和zptr对应实参所存放的存储单元地址分别为:R[ebp]+8、R[ebp]+12、
R[ebp]+16。
(2)函数func的C语言代码如下:
void func(int *xptr, int *yptr, int *zptr) {
int tempx=*xptr; int tempy=*yptr; int tempz=*zptr; *yptr=tempx;
}
*zptr = tempy; *xptr = tempz;
7.参考答案:
(1)R[edx]=x (2)R[edx]=x+y+4 (3)R[edx]=x+8*y (4)R[edx]=y+2*x+12 (5)R[edx]=4*y (6)R[edx]=x+y 8.参考答案:
(1)指令功能为:R[edx]←R[edx]+M[R[eax]]=0x00000080+M[0x8049300],寄存器EDX中内容改变。改变后的
内容为以下运算的结果:00000080H+FFFFFFF0H
0000 0000 0000 0000 0000 0000 1000 0000 + 1111 1111 1111 1111 1111 1111 1111 0000 1 0000 0000 0000 0000 0000 0000 0111 0000
因此,EDX中的内容改变为0x00000070。根据表可知,加法指令会影响OF、SF、ZF和CF标志。OF=0,ZF=0,SF=0,CF=1。
(2)指令功能为:R[ecx]←R[ecx]-M[R[eax]+R[ebx]]=0x00000010+M[0x8049400], 寄存器ECX中内容改变。
改变后的内容为以下运算的结果:00000010H-H
0000 0000 0000 0000 0000 0000 0001 0000 + 0111 1111 1111 1111 1111 1111 1111 1000 0 1000 0000 0000 0000 0000 0000 0000 1000
因此,ECX中的内容改为0x。根据表可知,减法指令会影响OF、SF、ZF和CF标志。OF=1,ZF=0,SF=1,CF=1?0=1。
(3)指令功能为:R[bx]←R[bx] or M[R[eax]+R[ecx]*8+4],寄存器BX中内容改变。改变后的内容为以下运
算的结果:0x0100 or M[0x8049384]=0100H or FF00H
0000 0001 0000 0000 o1111 1111 0000 0000 1111 1111 0000 0000
因此,BX中的内容改为0xFF00。由节可知,OR指令执行后OF=CF=0;因为结果不为0,故ZF=0;因为最高位为1,故SF=1。
(4)test指令不改变任何通用寄存器,但根据以下“与”操作改变标志:R[dl] and 0x80
1000 0000 and1000 0000 1000 0000
由节可知,TEST指令执行后OF=CF=0;因为结果不为0,故ZF=0;因为最高位为1,故SF=1。
(5)指令功能为:M[R[eax]+R[edx]]←M[R[eax]+R[edx]]*32,即存储单元0x8049380中的内容改变为以下运
算的结果:M[0x8049380]*32=0x908f12a8*32,也即只要将0x908f12a8左移5位即可得到结果。 1001 0000 1000 1111 0001 0010 1010 1000<<5
=0001 0001 1110 0010 0101 0101 0000 0000
因此,指令执行后,单元0x8049380中的内容改变为0x11e25500。显然,这个结果是溢出的。但是,根据表可知,乘法指令不影响标志位,也即并不会使OF=1。
(6)指令功能为:R[cx] ←R[cx]-1,即CX寄存器的内容减一。
0000 0000 0001 0000 + 1111 1111 1111 1111 1 0000 0000 0000 1111
因此,指令执行后CX中的内容从0x0010变为0x000F。由表可知,DEC指令会影响OF、ZF、SF,根据上述运算结果,得到OF=0,ZF=0,SF=0。
9.参考答案:
movl 12(?p), ìx 1 1执行
5 testb $0x80, %dl 1 1执行 7 addb %dl, (êx) 1:
因为C语言if语句中的条件表达式可以对多个条件进行逻辑运算,而汇编代码中一条指令只能进行一种逻辑运算,并且在每条逻辑运算指令生成的标志都是存放在同一个EFLAGS寄存器中,所以,最好在一条逻辑指令后跟一条条件转移指令,把EFLAGS中标志用完,然后再执行另一次逻辑判断并根据条件进行转移的操作。 (2)按照书中图给出的“if () goto …”语句形式写出汇编代码对应的C语言代码如下:
1 void comp(char x, int *p) 2 {
3 if (p!=0) 4 if (x<0) 5 *p += x; 6 }
13.参考答案:
1 int func(int x, int y) 2 {
3 int z = x*y ;
4 if ( x<=-100 ) { 5 if ( y>x ) 6 z = x+y ; 7 else
8 z = x-y ; 9 } else if ( x>=16 ) 10 z = x &y ; 11 return z; 12 }
14.参考答案:
(1)每个入口参数都要按4字节边界对齐,因此,参数x、y和k入栈时都占4个字节。 1 movw 8(?p), %bx 1:
5 movw %si, %dx 2 2 13 cmpw %cx, %si 1 1 15 .L2:
16 movswl %bx, êx & 0x1,因此f1用于检测x的奇偶性,当x中有奇数个1,则返回为1,否则返回0。
16.参考答案:
函数sw只有一个入口参数x,根据汇编代码的第2~5行指令知,当x+3>7时转标号.L7处执行,否则,按照跳
转表中的地址转移执行,x与跳转目标处标号的关系如下: x+3=0:.L7 x+3=1:.L2 x+3=2:.L2
x+3=3:.L3 x+3=4:.L4 x+3=5:.L5 x+3=6:.L7 x+3=7:.L6
由此可知,switch (x) 中省略的处理部分结构如下: case -2: case -1:
…… 2标号处指令序列对应的语句 break;
case 0:
…… 3标号处指令序列对应的语句 break;
case 1:
……. 4标号处指令序列对应的语句
break; case 2:
…… 5标号处指令序列对应的语句 break;
case 4:
…… 6标号处指令序列对应的语句
break;
default:
…… 7标号处指令序列对应的语句
17.参考答案:
根据第2、3行指令可知,参数a是char型,参数p是指向short型变量的指针;根据第4、5行指令可知,参
数b和c都是unsigned short型,根据第6行指令可知,test的返回参数类型为unsigned int。因此,test的原型为:
unsigned int test(char a, unsigned short b, unsigned short c, short *p); 18.参考答案:
每次执行pushl指令后,R[esp]=R[esp]-4,因此,第2行指令执行后R[esp]=0xbc00001c。
(1)执行第3行指令后,R[ebp]=R[esp]=0xbc00001c。到第12条指令执行结束都没有改变EBP的内容,因而
执行第10行指令后,EBP的内容还是为0xbc00001c。执行第13行指令后,EBP的内容恢复为进入函数funct时的值0xbc000030。
(2)执行第3行指令后,R[esp]=0xbc00001c。执行第4行指令后R[esp]=
R[esp]-40=0xbc00001c-0x28=0xbbfffff4。因而执行第10行指令后,未跳转到scanf函数执行时,ESP中的内容为0xbbfffff4-4=0xbbfffff0;在从scanf函数返回后ESP中的内容为0xbbfffff4。执行第13行指令后,ESP的内容恢复为进入函数funct时的旧值,即R[esp]=0xbc000020。
(3)第5、6两行指令将scanf的第三个参数&y入栈,入栈的内容为R[ebp]-8=0xbc000014;第7、8两行指令
将scanf的第二个参数&x入栈,入栈的内容为R[ebp]-4=0xbc000018。故x和y所在的地址分别为0xbc000018和0xbc000014。
(4)执行第10行指令后,funct栈帧的地址范围及其内容如下:
0xbc00001c 0xbc000018 0xbc000014 0xbc000010 0xbc00000c 0xbc000008 0xbc000004 0xbc000000 0xbbfffff0xbbfffff0xbbfffff0xbbfffff
0xbc000014 0xbc000018 0x804c000 从scanf返回的地ESP
0xbc000030 x=15 EBP 栈帧底部
y=20 19.参考答案:
第1行汇编指令说明参数x存放在EBX中,根据第4行判断x=0则转.L2,否则继续执行第5~10行指令。根据第5、6、7行指令可知,入栈参数nx的计算公式为x>>1;根据第9、10、11行指令可知,返回值为(x&1)+rv。由此推断出C缺失部分如下:
1 int refunc(unsigned x) { 2 if ( x==0 )
3 return 0 ; 4 unsigned nx = x>>1 ;
5 int rv = refunc(nx) ;
6 return (x & 0x1) + rv ; 7 }
该函数的功能为计算x的各个数位中1的个数。 20.参考答案:
在IA-32中,GCC为数据类型long double型变量分配12字节空间,实际上只占用10个字节。
数组 char A[10] int B[100] short short long E[10] long *F[10] double 4 40 &F[0] &F[0]+4i *C[5] **D[6] double 元素大小(B) 数组大小(B) 1 4 4 4 12 10 400 20 24 120 起始地址 &A[0] &B[0] &C[0] &D[0] &E[0] 元素i的地址 &A[0]+i &B[0]+4i &C[0]+4i &D[0]+4i &E[0]+12i 21.参考答案: 表达式 S S+i S[i] &S[10] 类型 short * short * short short * 值 汇编代码 leal (íx), êx leal (íx, ìx, 2), êx movw (íx, ìx, 2), %ax leal 20(íx), êx AS AS+2*i M[AS+2*i] AS+20