25考研计算机组成原理复习·4.3程序的机器级代码表示

目录

高级语言与机器级代码之间的对应

常见的算术运算指令

常见的逻辑运算指令

AT&T格式 v.s. Intel格式

选择语句的机器级表示

无条件转移指令——jmp

条件转移指令——jxxx

示例:选择语句的机器级表示

循环语句的机器级表示

用条件转移指令实现循环

用loop指令实现循环

函数调用机器级表示

call、ret指令

如何访问栈帧?

访问栈帧数据:push、pop指令

访问栈帧数据:mov指令

如何切换栈帧?

栈帧内包含哪些内容?

参数、返回值传递

高级语言与机器级代码之间的对应

  • 指令的作用?1.改变程序执行流 2.处理数据
  • 指令格式:
    • 操作码:怎么处理?
    • 地址码:数据在哪儿?
      • 在寄存器里。在汇编指令中,给出寄存器名(通用寄存器:eax、ebx、ecx、edx;变址寄存器:esi、edi;堆栈寄存器:ebp、esp
      • 在主存里:在汇编指令中,给出读写长度主存地址dword ptr[地址] #32bitword ptr[地址] #16bittype ptr[地址] #8bit
      • 在指令里:在汇编指令中,直接给出常量,即“立即寻址”;可用十进制表示、也可用十六进制表示(通常用h结尾)

常见的算术运算指令

功能英文汇编指令注释
addadd d,s#计算d+s,结果存入d
subtractsub d,s#计算d-s,结果存入d
multiply

mul d,s

imul d,s

#无符号数d*s,乘积存入d

#有符号数d*s,乘积存入d

divide

div s

idiv s

#无符号数除法edx:eax/s,商存入eax,余数存入edx

#有符号数除法edx:eax/s,商存入eax,余数存入edx

取负数negativeneg d#将d取负数,结果存入d
自增++increaseinc d#将d++,结果存入d
自减--decreasedec d#将d- -,结果存入d

常见的逻辑运算指令

功能英文汇编指令注释
andand d,s#将d、s逐位相与,结果放回d
oror d,s#将d、s逐位相或,结果放回d
notnot d#将d逐位取反,结果放回d
异或exclusive orxor d,s#将d、s逐位异或,结果放回d
左移shift leftshl d,s#将d逻辑左移s位,结果放回d(通常s是常量)
右移shift rightshr d,s#将d逻辑右移s位,结果放回d(通常s是常量)

AT&T格式 v.s. Intel格式

AT&T格式Intel格式
目的操作数d、源操作数s

op s,d

注:源操作数在左,目的操作数在右

op d,s

注:源操作数在右,目的操作数在左

寄存器的表示

mov %ebx,%eax

注:寄存器名之前必须加“%”

mov eax,ebx

注:直接写寄存器名即可

立即数表示

mov $985,%eax

注:立即数之前必须加“$”

mov eax,985

注:直接写数字即可

主存地址表示

mov %eax,(af996h)

注:用“()”

mov [af996h],eax

注:用“[]”

读写长度表示

movb $5,(af996h)

movw $5,(af996h)

movl $5,(af996h)

addb $4,(af996h)

注:指令后加b、w、l分别表示读写长度为byte、word、dword

mov byte ptr[af996h],5

mov word ptr[af996h],5

mov dword ptr[af996h],5

add byte ptr[af996h],4

注:在主存地址前说明读写长度byte、word、dword

主存地址偏移量表示

movl -8(%ebx),%eax

注:偏移量(基址)

movl 4(%ebx,%eax,32),%eax

注:偏移量(基址,变址,比例因子)

mov eax,[ebx - 8]

注:[基址+偏移量]

mov eax,[ebx + eax*32 +4]

注:[基址+变址*比例因子+偏移量]

选择语句的机器级表示

无条件转移指令——jmp

mov eax,7
mov ebx,6
jum NEXT
mov ecx,ebx
NEXT: #用“标号”锚定位置 特征——有冒号,名字可以自己取
mov ecx,eax

条件转移指令——jxxx

cmp a,b #比较a和b两个数

je<地址>  #jump when equal,若a=b则跳转
jne<地址>  #jump when not equal,若a!=b则跳转
jg<地址>  #jump when greater than,若a>b则跳转
jge<地址>  #jump when greater than or equal to,若a>=b则跳转
jl<地址>  #jump when less than,若a<b则跳转
jle<地址>  #jump when less than or equal to,若a<=b则跳转

示例:选择语句的机器级表示

if(a > b){
	c = a;
}else{
	c = b;
}
mov eax,7
mov ebx,6
cmp eax,ebx
jg NEXT
mov ecx,ebx
jum END
NEXT:
mov ecx,eax
END:

循环语句的机器级表示

用条件转移指令实现循环

int result = 0;
for(int i = 1;i <= 100;i++){
	result += i;
}//求1+2+3+…+100

用条件转移指令实现循环,需要4个部分构成:

  1. 循环前的初始化
  2. 是否直接跳过循环?
  3. 循环主题
  4. 是否继续循环?
mov eax,0  #1.用eax保存result,初值为0
mov edx,1  #1.用edx保存i,初始值为1
cmp edx,100  #2.比较i和100
jg L2  #2.若i>100,转跳到L2执行
L1:  #循环主体
add eax,edx  #3.实现 result += i
inc edx  #3.inc自增指令,实现i++
cmp edx,100  #4.i和100
jle L1  #4.若i <= 100,转跳到L1执行
L2:  #跳出循环主体

用loop指令实现循环

for(int i = 500;i > 0;i--){
	做某些处理;
}//循环500轮
mov ecx,500  #用ecx作为循环寄存器
Looptup:  #循环的开始
...
做某些处理
...
loop Looptop  #ecx--,若ecx!=0,跳转到Looptop
#等价于dec ecx 
#cmp ecx,0
#jne Looptop

理论上,能用loop指令实现的功能一定能用条件转移指令实现。

使用loop指令可能会使代码更清晰简洁。

补充:loopx指令——loopnz,loopz

        loopnz——当ecx≠0&&ZF==0时,继续循环

        loopz——当ecx≠0&&ZF==1时,继续循环

函数调用机器级表示

call、ret指令

  1. 函数调用指令:call<函数名>

    函数返回指令:ret

  2. call指令的作用:

    1. IP旧值压栈保存(保存在函数的栈帧顶部)(效果相当于 push IP)
    2. 设置IP新值,无条件转移至被调用函数的第一条指令(效果相当于jmp add)
  3. ret指令的作用:从函数的栈帧顶部找到IP旧值,将其出栈并恢复IP寄存器

如何访问栈帧?

栈帧(Stack Frame)保存函数大括号内定义的局部变量,保存函数调用相关信息

访问栈帧数据:push、pop指令

push、pop指令实现入栈、出栈操作,x86默认以4字节为单位。指令格式如下:

        push 🏇  //先让esp减4,再将🏇压入(🏇可以是立即数、寄存器、主存地址)

        pop 🐘  //栈顶元素出栈写入🐘,再让esp加4(🐘可以是寄存器、主存地址)

访问栈帧数据:mov指令

sub esp,12 #栈顶指针-12
mov[esp+8],eax  #将eax的值复制到主存[esp+8]
mov[esp+4],985  #将985复制到主存[esp+4]
mov eax,[ebp+8]  #将主存[ebp+8]的值复制到eax
mov [esp],eax  #将eax的值复制到主存[esp]
add esp,8  #栈顶指针+8

可以用mov指令,结合esp、ebp指针访问栈帧数据

可以用减法/加法指令,即sub/add修改栈顶指针esp的值

如何切换栈帧?

call指令的作用:

        将IP旧值压栈保存(效果相当于 push IP)

        设置IP新值,无条件转移至被调用函数的第一条指令(效果相当于jmp add)


push ebo #保存上一层函数的栈帧基址(ebp旧值)

mov ebp,esp #设置当前函数的栈帧基址(ebp新值)

 在每个函数开头的“例行处理”。两条指令等价于enter

mov esp,ebp #让esp指向当前栈帧的底部

pop ebp #将esp所指元素出栈,写入寄存器ebp

 在每个函数ret前的“例行处理”。两条指令等价于leave


ret指令的作用:从函数的栈帧顶部找到IP旧值,将其出栈并恢复IP寄存器

栈帧内包含哪些内容?

  1. gcc编译器将每个栈帧大小设置为16B的整数倍,因此战阵内可能出现空闲未使用的区域。
  2. 通常将局部变量集中存储在栈帧底部区域
  3. 通常将调用参数集中存储在栈帧顶部区域
  4. 栈帧最底部一定是上一层栈帧基址(ebp旧值)
  5. 栈帧最顶部一定是返回地址(当前函数的栈帧除外)

参数、返回值传递

  1. 在cal指令前,将调用参数写入栈帧顶部区域
  2. 在ret指令前,将函数返回值写入eax寄存器

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Annabelle.02

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值