当前位置: 首页 > news >正文

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寄存器

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Pytorch构建网络模型结构都有哪些方式
  • 通过C# 读取PDF页面大小、方向、旋转角度
  • 攀高行为检测识别摄像机
  • JavaWeb系列四: DOM 上
  • 多线程篇(基本认识 - 线程相关API)(持续更新迭代)
  • 数学建模笔记(四):熵权
  • 排序算法-堆排序
  • 甲方(北汽)渗透测试面试经验分享
  • Nginx: 负载均衡场景下上游服务器异常时的容错机制
  • github访问加速项目@一键部署自动更改host修改加速Github访问
  • k8s调度器Scheduler
  • Lodash——JavaScript中的工具库
  • buuctf [MRCTF2020]hello_world_go
  • 速盾:服务器接入cdn后上传图片失败怎么解决?
  • 主控和从控!!!
  • 【node学习】协程
  • canvas 绘制双线技巧
  • Docker 笔记(1):介绍、镜像、容器及其基本操作
  • export和import的用法总结
  • JAVA SE 6 GC调优笔记
  • java8 Stream Pipelines 浅析
  • JS题目及答案整理
  • PV统计优化设计
  • React-redux的原理以及使用
  • SpiderData 2019年2月23日 DApp数据排行榜
  • use Google search engine
  • 分布式事物理论与实践
  • 好的网址,关于.net 4.0 ,vs 2010
  • 前端自动化解决方案
  • 如何实现 font-size 的响应式
  • 如何优雅地使用 Sublime Text
  • 腾讯大梁:DevOps最后一棒,有效构建海量运营的持续反馈能力
  • 携程小程序初体验
  • 新书推荐|Windows黑客编程技术详解
  • 移动端唤起键盘时取消position:fixed定位
  • 移动端解决方案学习记录
  • 硬币翻转问题,区间操作
  • 用Python写一份独特的元宵节祝福
  • 阿里云服务器购买完整流程
  • # Java NIO(一)FileChannel
  • # 飞书APP集成平台-数字化落地
  • #Datawhale AI夏令营第4期#AIGC文生图方向复盘
  • #if 1...#endif
  • #include到底该写在哪
  • #laravel 通过手动安装依赖PHPExcel#
  • #基础#使用Jupyter进行Notebook的转换 .ipynb文件导出为.md文件
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • (1)Hilt的基本概念和使用
  • (14)学习笔记:动手深度学习(Pytorch神经网络基础)
  • (30)数组元素和与数字和的绝对差
  • (BAT向)Java岗常问高频面试汇总:MyBatis 微服务 Spring 分布式 MySQL等(1)
  • (delphi11最新学习资料) Object Pascal 学习笔记---第13章第6节 (嵌套的Finally代码块)
  • (javaweb)Http协议
  • (Java实习生)每日10道面试题打卡——JavaWeb篇
  • (JSP)EL——优化登录界面,获取对象,获取数据