【学习时间:10小时】
【学习内容:第三章:程序的机器表示】
1 DOS时代的平坦模式,不区分用户空间和内核空间,很不安全;
2 8086的分段模式;
3 IA32的带保护模式的平坦模式
1)指令集体系结构(Instruction set architecture,ISA)——定义指令格式以及每条指令执行之后对状态的影响。大多数ISA将程序行为描述成按顺序执行的;
2)虚拟地址
1)PC,即程序计数器,用来指示将要执行的下一条指令在存储器中的地址;
2)整数寄存器,存储数据;条件码寄存器,保存逻辑指令状态信息;等
pushl %ebp //将该寄存器内容全部压入程序栈
movl %esp,%ebp
……
addl %eax,accum
popl %ebp
od code.o | more
od code.o > code.txt
1)Ea——操作数值:R[Ea]
2)(Ea)——操作数值:M(R[Ea])
3)Imm(Ea)——操作数值:M(Imm+R[Ea])
思考一下:CMP和SUB用在什么地方?
【一般来说,CMP应该是用在对操作数进行测试的时候,比如,可以测试某个数与已知数的大小关系等;而SUB执行的是减法操作,用于普通运算中】
1)无条件跳转——jmp.<标号> 跳转到标号所指示的语句处;jmp *<操作数指示符> 【注意:如果形如%eax,即以%eax中的值作为跳转目标;而形如(%eax)则是以其中的值作为地址,读出跳转目标】 2)有条件跳转——类似于SET类指令,是根据条件码或者其组合来跳转
loop:
body-statement
t = test-sxpr;
if(t)
goto loop;
t = test-sxpr;
if(!t)
goto done;
loop:
body-statement
t = test-sxpr;
if(t)
goto loop;
done:
1)call指令:后接被调用过程的起始的指令地址。效果是将返回地址入栈,并跳转到被调用过程的起始处。
2)ret指令:从栈中弹出地址,并跳转到这个位置。
【二者配合,实现函数调用时的衔接:即,call类似于先行的探险者,将迷宫入口处的地址存到某个安全的地方,然后探索迷宫(函数);ret类似于保障人员,在探险完成之后将该地址取出来,带领程序回到最初的入口处,接着走大路(主程序)】
movb $0xf,(%bl) ---目的操作数只能是一个寄存器或者一个存储器地址。(%bl)表示一个值
movw (%eax),4(%esp)---目的操作数与源操作数不能都是存储器
movb %si, 8(%ebp)---指令后缀与寄存器地址不匹配
movl 8(%ebp),%edi
movl 12(%ebp),%edx
movl 16(%ebp),%ecx
movl (%edx),%ebx
movl (%ecx),%esi
movl (%edi),%eax
movl %eax,(%edx)
movl %ebx,(%ecx)
movl %esi,(%edi)
代码如下:
void decode1(int *xp,int *yp,int *zp)
{
int x=*xp;
int y =*yp;
int z = *zp;
*yp = x;
*zp = y;
*xp = z;
}
movl 12(%ebp),%eax
xorl 8(%ebp),%eax
sarl $3,%eax
notl %eax
subl 16(%ebp),%eax
C语言代码:
int arith(int x,int y,int z)
{
int t1 = x^y;
int t2 = 3*t1;
int t3 = ~t2;
int t4 = t3-z;
return t4;
}
int test(data_t a)
{
return a TEST 0;
}
根据以下每条指令序列,确定哪种数据类型和比较TEST会使编译器产生这样的代码?
A. testl %eax,%eax setne %al
[既然是l,表明是32位,且data_t可以是int,unsigned和指针;而ne表示比较类型是 !=,对有无符号的数字都成立;对于unsigned,比较还可以是>]
B. testb %al,%al setg %al
[既然是b,表明是16位,且比较是 == ;则data_t应该是short或者unsigned short]
A.
804828f:74 05 je XXXXXXX
8048291:E8 10 00 00 00 CALL 80482B4
XXXXXXXX:0x8048291+0x05 = 0x8048296[利用P129所讲,程序计数器的值是跳转指令之后的那条指令的地址;而更新计数器又是执行一条指令的第一步,所以要加上原来的地址] B.
8048357:72 e7 jB XXXXXXX
8048359:c6 05 10 a0 04 08 01 movb $0x1,0x804a010
XXXXXXX:0xe7(补码)+0x8048359 = 0x8048359-25 = 8048340
void cond(int a,int *p)
{
if(p&&a>0)
*p +=a;
}
按照与汇编代码等价的C语言goto版本,写一个与之等价的C语言代码。 答:
void goto_cond(int a,int *p)
{
if(p == 0)
goto done;
if(a<=0)
goto done;
*p +=a;
done:
return;
}
为什么C语言只有一个条件语句;而汇编中有两个分支呢? 【第一个条件分支是&&表达式实现的一部分;如果对p非空的测试失败,代码会跳过对a的测试】
movl 8(%edp),%edx //x at %edp+8
movl $0,%eax
testl %edx,%edx
je .L7
.L10:
xorl %edx,%eax
shrl %edx //shift right by 1
jne .L10
.L7:
andl $1,%eax
则对应的C语言代码是:
int fun_a(unsigned x)
{
int val = 0;
while(x!=0)
{
val = val ^ x;
x>> = 1;
}
return val & 0x1;
}
这段代码的功能? 【如果x有奇数个1,就返回1;如果有偶数个1,就返回0】
movl 8(%ebp),%ebx //x at %ebp+8
movl $0,%eax
movl $0,%ecx
.L13:
leal (%eax,%eax),%edx
movl %ebx,%eax
andl $1,%eax
orl %edx,%eax
shrl %edx
addl $1,%ecx
cmpl $32,%ecx
jne .L13
补充以下C语言源代码
int fun_b(unsigned x)
{
int val = 0;
int i;
for(i =0;i<32;i++)
{
val = (val<<1) | (x & 0x1);
x>> =1;
}
return val;
}
作用? 【把x的位(十六进制)翻转过来填入val】
int switcher(int a,int b,int c)
{
int answer;
switch(a)
{
case 5 :
c = b ^ 15;
case 0 :
answer = c+112;
case 2 :
case 7 :
answer = c+6;
break;
case 4 :
answer = a;
break;
default :
answer = b;
}
return answer;
}
call next
next:
popl %eax
A.寄存器%eax被设置成了什么值? 【popl】 B.解释为什么这个调用没有与之匹配的ret指令 【这不是一个真正的过程调用,因为根本是按照与指令相同的顺序进行的】 C.这段代码完成了什么功能? 【这是IA32中将程序计数器中的值放到整数计数器中的唯一办法】
jmp *<操作数指示符【注意:如果形如%eax,即以%eax中的值作为跳转目标;而形如(%eax)则是以其中的值作为地址,读出跳转目标】 那么,如果程序中有这种语句,跳到目标值之后会怎么样呢?
jmp *.L7(,%eax,4)
然而,该段代码中并没有标识.L7的位置。那么jmp指令如何寻址?
根据图3-20的汇编代码,填写补充C源代码.答案如下:
int switcher(int a,int b,int c) { int answer; switch(a) { case 5 : c = b ^ 15; case 0 : answer = c+112; case 2 : case 7 : answer = c+6; break; case 4 : answer = a; break; default : answer = b; } return answer; }
其中,关于
case 4 :
answer = a;
break;
答案中解释为:
GCC对程序进行了优化,将answer = 4优化为answer = a。
为什么?
call next next: popl %eax
C.这段代码完成了什么功能? 【这是IA32中将程序计数器中的值放到整数计数器中的唯一办法】
这句解释是什么意思呢?
在这周的自学中,主要是学习了机器内执行程序的时候所发生的动态变化。要究动态,就必须了解静态的内部“参量”;有前面打下的基础,才有后面学得懂、学得透的可能性。在大的方面上,更是因为有上学期汇编语言的基础,才能保证流畅阅读基础的汇编代码,而不用时时刻刻“查字典”。在学习上,也有类似于文学作品中那样所谓的“伏笔”——自己奠定了什么样的基础,决定了有什么样的起承转合。