汇编语言

似梦清欢
• 阅读 910

汇编语言 CPU编译后的可执行程序是项目名称命名的exe文件。 汇编指令分为两个类型: 操作码字段:表征指令的操作特性和功能,是指令的唯一标识。(要做什么操作?) 地址码字段:指定参与操作的操作数的地址码。(操作哪里的内存?)

指令中指定操作数存储位置的字段称为地址码,地址码中可以包含存储器地址,也可包含寄存器编号。 指令中可以有一个、两个或者三个操作数,也可没有操作数,根据一条指令有几个操作数地址,可将指令分为零地址指令、一地址指令、二地址指令、三地址指令。 汇编语言

汇编语言 汇编语言 二地址指令格式中,从操作数的物理位置来说有可归为三种类型: ①寄存器-寄存器(RR)型指令:需要多个通用寄存器或个别专用寄存器,从寄存器中取操作数,把操作结果放入另一个寄存器,机器执行寄存器-寄存器型的指令非常快,不需要访问内存。 ②寄存器-存储器(RS)型指令:执行此类指令时,既要访问内存单元,又要访问寄存器。 ③存储器-存储器(SS)型指令:操作时都是涉及内存单元,参与操作的数都是放在内存里,从内存某单元中取操作数,操作结果存放至内存另一单元中,因此机器执行指令需要多次访问内存。 (寄存器:register;存储器:storage。)

( test.c main.c ) --1--> (test.i main.i) --2--> (test.s main.s) --3--> (test.o main.o) --4--> (a.out) ::: tip C代码编译成可执行程序经过4步: (1)预处理:展开头文件、宏替换、删除代码注释、条件编译,不检查语法(.1) (2)编译:检查语法,将预处理后文件编译生成汇编文件(.s) (3)汇编:汇编代码转换成机器码(.obj) (4)链接:链接调用的库函数生成可执行文件(.exe) :::

VS生成汇编的设置步骤: 汇编语言 汇编语言 VS的汇编后缀是cod。 Clion生成汇编的步骤: 底边栏“终端”-输入“gcc (-m32 -masm=intel)-S -fverbose-asm 文件名.c”,回车生成文件名.s的汇编文件。

Clion生成机器码的步骤: gcc -m32 -g -o 文件名 文件名.c objdump --source 文件名.exe >文件名.dump


汇编常用指令

汇编语言 汇编指令可以分为数据传送指令、逻辑计算指令、控制流指令。 ::: warning 在汇编中,寄存器访问内存时需要加方括号。 ::: 汇编语言 Intel汇编指令:

数据传送指令:

①mov指令:将第二个操作数(寄存器的内容、内存中的内容或常数值)复制到第一个操作数(寄存器或内存)。但不能用于直接从内存复制到内存。 汇编语言 ②push指令:将操作数压入内存的栈,常用于函数调用。ESP是栈顶,压栈前先将ESP值减4(栈增长方向与内存地址增长方向相反),然后将操作数压入ESP指示的地址。 汇编语言 ③pop指令:与 push 指令相反,pop指令执行的是出栈工作,出栈前先将ESP指示的地址中的内容出栈,然后将 ESP值加4。

算术与逻辑运算指令:

①add/sub指令:add指令将两个操作数相加,相加的结果保存到第一个操作数中。sub指令用于两个操作数相减,相减的结果保存到第一个操作数中。 汇编语言 ②inc/dec指令:inc、dec 指令分别表示将操作数自加1、自减1。 汇编语言 ③imul指令:带符号整数乘法指令,有以下两种格式: 两个操作数,将两个操作数相乘,将结果保存在第一个操作数中,第一个操作数必须为寄存器; 三个操作数,将第二个和第三个操作数相乘,将结果保存在第一个操作数中,第一个操作数必须为寄存器。 汇编语言 乘法操作结果可能溢出,则编译器置溢出标志OF=1,以使CPU调出溢出异常处理程序。 ④idiv 指令:带符号整数除法指令,只有一个操作数即除数,而被除数则为edx:eax 中的内容(64位整数),操作结果有两部分:商和余数。商送到eax,余数则送到edx。 汇编语言 ⑤and/or/xor指令。and、or、xor指令分别是按位与、按位或、按位异或操作指令,用于操作数的位操作(按位与、按位或、按位异或),操作结果放在第一个操作数中。 汇编语言 ⑥not指令:位翻转指令,将操作数的每一位翻转,即0→1、1→0。 汇编语言 ⑦neg指令:取负指令。 汇编语言 ⑧shl/shr指令。逻辑移位指令,shl为逻辑左移,shr为逻辑右移,第一个操作数表示被操作数,第二个操作数指示移位的位数。 汇编语言 ⑨lea指令:地址传送指令,将有效地址传送到指定的的寄存器。 汇编语言

控制流指令:

x86处理器维持着一个指示当前执行指令的指令指针(IP),当一条指令执行后,此指针自动指向下一条指令。IP寄存器不能直接操作,但可以用控制流指令更新。通常用标签(label)指示程序中的指令地址,在x86汇编代码中,可在任何指令前加入标签。 汇编语言 如上图使用begin (begin代表标签名,可以为别的名字)指示了第二条指令,控制流指令通过标签就可以实现程序指令的跳转。 ①jmp指令:jmp指令控制IP转移到label所指示的地址(从label中取出指令执行)。 汇编语言 ②jconditio指令:条件转移指令,依据CPU状态字中的一系列条件状态转移。CPU状态字中包括指示最后一个算术运算结果是否为0,运算结果是否为负数等。类似关系运算符。 汇编语言 ③cmp/test指令。cmp指令用于比较两个操作数的值;test指令对两个操作数进行逐位与运算。 这两类指令都不保存操作结果,仅根据运算结果设置CPU状态字中的条件码。 cmp和test指令通常和jcondition指令搭配使用。 汇编语言 ④call/ret指令:分别用于实现子程序(过程、函数等)的调用及返回。 汇编语言 ::: tip call指令首先将当前执行指令地址入栈,然后无条件转移到由标签指示的指令。与其他简单的跳转指令不同,call指令保存调用之前的地址信息(当call指令结束后,返回调用之前的地址)。ret指令实现子程序的返回机制,ret指令弹出栈中保存的指令地址,然后无条件转移到保存的指令地址行。call和ret是程序(函数)调用中最关键的两条指令。 :::

条件码

编译器通过条件码(标志位)设置指令和各类转移指令来实现程序中的选择结构语句。 条件码(标志位) 除了整数寄存器,CPU还维护着一组条件码(标志位)寄存器,它们描述了最近的算术或逻辑运算操作的属性。可以检测这些寄存器来执行条件分支指令。 常用条件码如下: 汇编语言 OF和SF对无符号数运算来说没有意义,而CF对带符号数运算来说没有意义。

判断是否溢出最简单的是如果正数相加结果变为负数则溢出,负数相加变正数则溢出。 两个十六进制数判断是否溢出: 汇编语言 即数据位高位和符号位高位进位不一样的时候会发生溢出。

常见的算术逻辑运算指令(add、sub、imul、or、and、shl、inc、dec、not、sal 等)会设置条件码。但有两类指令只设置条件码而不改变任何其他寄存器,即cmp和test指令,cmp指令和sub指令的行为一样,test指令与and指令的行为一样,但它们只设置条件码,而不更新目的寄存器。


变量赋值汇编

汇编语言 汇编语言 CPU运行C代码时去掉了变量名,数据是从一个空间拿到另一个空间的过程,即编译后的代码中没有变量名。 访问所有变量的空间都是通过栈指针(esp存放,也可称为栈顶指针)的偏移来获取对应变量内存空间的数据。 汇编语言 call调用函数。 mov将第二个操作数复制到第一个操作数的位置。 arr中每一个整型元素占4个字节空间,三个元素的位置分别是距离栈顶指针24、28、32字节。 (esp存了main函数栈顶指针内存地址,每次+1偏移一个字节) ::: tip 英特尔汇编中,DWORD表示4个字节,word表示2个字节,byte表示1个字节。 ::: DWORD PTR可以看作是强制类型转换,表示将元素1存在栈顶指针偏移后指向的起始位置向后四个字节的位置(一个整型的大小)。 汇编语言 将常量5存放在esp存放的栈指针向后偏移44字节的位置,即变量i的空间。 汇编语言 将常量10存放在esp存放的栈指针向后偏移40字节的位置,即变量j的空间。 汇编语言 先将[esp+32]内的数据放进寄存器eax中,再把eax中的值放进内存空间[esp+44]。 (汇编指令不支持内存到内存的拷贝,不能将[esp+32]直接拷贝到[esp+44]) 汇编语言 汇编指令如为mov eax,DWORD PTR [esp+24],意为指向[esp+24]开始向下4个字节的内存空间内。 lea eax,[esp+24]可以取到[esp+24]指向的内存空间的地址,取地址时不关心类型,不需要DWORD PTR等。 将[esp+24]的地址放进寄存器eax中。eax编译器备注为tmp90,将tmp90放进p中。

::: warning 在英特尔的汇编中,针对内存时会加DWORD PTR,寄存器间的操作因为寄存器长度是固定的WORD,不需要加WORD。 :::


选择循环汇编
#include <stdio.h>

int main() {
    int i=5;
    int j=10;
    if(i<j)
    {
        printf("i is small\n");
    }
    for(i=0;i<5;i++)
    {
        printf("this is loop\n");
    }
    return 0;
}

汇编语言 text表示文字常量区,存放着字符串常量,LC0和LC1分别表示两个字符串常量的地址。 汇编语言 intel汇编不能操作两个内存,先将变量i放进eax寄存器,然后使用cmp指令比较大小,前一个操作数减后一个操作数,然后设置条件码(条件码是CPU设置的,汇编中看不到) jge L2表示如果前一个操作数大于等于后一个操作数,即eax寄存器大于等于DWORD PTR [esp+24]时,跳转到L2,否则继续向下执行,jge是根据条件码ZF和SF判断的。jge是条件转移指令,为if服务。 汇编语言 将0赋值给i后直接跳转L3。


函数调用汇编

汇编语言 汇编语言 此时esp是main函数的栈基指针 汇编语言 将a的地址赋给p,先将a的地址放在寄存器eax中,再把eax中的值赋给[esp+28]。

间接访问 汇编语言 DWORD PTR [esp+28]的地址值存放进寄存器eax,再将地址eax放在方括号内取出地址存放的值赋给eax。 p存放a的地址,即[esp+28]存放a的地址,再交给eax后,eax存放a的地址,[eax]取到eax中地址指向的值即a的值,赋给eax的值为5。 ::: tip 加[ ]表示间接取操作数,类似C语言中的指针。 :::

函数调用: 汇编语言 实参传递(值传递)。

点赞
收藏
评论区
推荐文章
桃浪十七丶 桃浪十七丶
3年前
计算机组成原理5.2指令执行过程
一、指令周期的概念:CPU从主存中取出并执行一条指令的时间被称为指令周期。一个指令周期包含若干机器周期(机器周期也称为CPU周期);一个机器周期包含若干时钟周期(时钟周期又称为节拍或者T周期或者CPU时钟周期,是CPU操作的最基本单位)。每个指令周期内的机器周期数量可以不同,每个机器周期内的时钟周期数量也可以不同。不同的指令的指令周期可能不同,如:1.注:分
桃浪十七丶 桃浪十七丶
3年前
计算机组成原理4.1指令格式
4.1.1指令的基本概念和指令的基本格式操作码:指明CPU进行什么操作。地址码:知指明CPU对谁进行操作。PC:程序计数器,每执行一条指令会1指向下一条指令。指令的概念和基本格式:是指一台计算机执行某种操作的命令,一台计算机的所有指令的集合构成指令集,也叫做指令系统,位于计算机的硬件和OS层面。不同计算机只能执行自己系统的指令,如Intel的x86架构,手
Wesley13 Wesley13
2年前
ARM与X86架构的对决
CISC(复杂指令集计算机)和RISC(精简指令集计算机)是当前CPU的两种架构。它们的区别在于不同的CPU设计理念和方法。早期的CPU全部是CISC架构,它的设计目的是 CISC要用最少的机器语言指令来完成所需的计算任务。RISC和CISC是设计制造微处理器的两种典型技术,虽然它们都是试图在体系结构、操作运行、软件硬件、编译时间和运行时间等诸多因素中做出
Wesley13 Wesley13
2年前
PIC中档单片机汇编指令详解(5)
位操作指令详述BCF数据寄存器指定位清0语法形式:BCFf,b操作数:f为数据寄存器的低7位地址(0x00~0x7F)B为数据位编号(0~7)执行时间:一个指令周期执行过程:使数据寄存器f的的b位清0状态标志影响:无说明:该指令可对任何数据寄存器的任意一个位置清0,常用于标志位的设定和清除,或者把某一管脚置成低电平。指
Wesley13 Wesley13
2年前
Java虚拟机(一):JVM简介
JVM简介Java虚拟机(JVM)是由Java虚拟机规范定义的,其上运行的是字节码指令集。这种字节码指令集包含一个字节的操作码(opcode),零至多个操作数(oprand),虚拟机规范明确定义了每种字节码指令完成的功能是什么以及需要多少个操作数。Java虚拟机上运行的class文件,这个文件中包含字节码指令流以及类定义的信息,所以Java虚
Wesley13 Wesley13
2年前
CPU知识点一览
关于CPU和程序的执行1、程序的运行过程,实际上是程序涉及到的、未涉及到的一大堆的指令的执行过程。当程序要执行的部分被装载到内存后,CPU要从内存中取出指令,然后指令解码(以便知道类型和操作数,简单的理解为CPU要知道这是什么指令),然后执行该指令。再然后取下一个指令、解码、执行,以此类推直到程序退出。2、这个取指、
Wesley13 Wesley13
2年前
JAVA字节码执行引擎总结
字节码指令大部分操作指令都有对应不同类型的不同指令,比如iloadistoreireturn表示加载(整形变量进操作数栈)、定义一个整形局部变量、返回一个int类型值return11》iconst2;ireturn编译期优化:直接将11定义为常量2运行时就不用再做计算了这段代码操作数栈的最大深度是2
Wesley13 Wesley13
2年前
Java多线程模式之流水线模式
流水线什么是流水线?在计算机中,对于一条具体的指令执行过程,通常可以分为五个部分:取指令,指令译码,取操作数,运算(ALU),写结果。前三步由指令控制器完成,后两步则由运算器完成。按照传统的方式,所有指令顺序执行,那么先是指令控制器工作,完成第一条指令的前三步,然后运算器工作,完成后两步,第一条指令执行完毕。然后第二条指令又是先
Stella981 Stella981
2年前
JVM基础命令
介绍java虚拟机的指令功能,至少能阅读java代码生成的字节码指令含义一、概述Java虚拟机采用基于栈的架构,其指令由操作码和操作数组成。操作码:一个字节长度(0~255),意味着指令集的操作码个数不能操作256条。操作数:一条指令可以有零或者多个操作数,且操作数可以是1个或者多个字节。编译后的代码没有采用操作数
ISA-L库调研
SIMD(singleinstructionmultipledata)单指令多数据流,能够复制多个操作数,并把它们打包在大型寄存器的一组指令集。以同步方式,在同一时间内执行同一条指令。