程序的机械级表示学习记录

程序的机械级表示学习记录

X86的三代寻址方式

  1. DOS时代的平坦模式,不区分用户空间和内核空间,很不安全。
  2. 8086的分段模式。
  3. IA32的带保护模式的平坦模式。

对于机械级编程的两种重要抽象

ISA:机械级程序的格式和行为,定义为指令集体系结构,它定义了处理器状态、指令的格式,以及每条指令对状态的影响。

虚拟地址:机器级程序使用的存储器地址,提供的存储器模型看上去是一个非常大的数组。存储器系统的实际实现是将多个硬件存储器和操作系统软件组合起来的。

在GCC中获得汇编代码与反汇编

获得汇编代码:gcc –S xxx.c –o xxx.s。

反汇编(将二进制目标文件还原为汇编代码)objdump –d xxx.o。

注:64位机器上想要得到32位代码:gcc –m32 –S xxx.c。

查看二进制文件

二进制文件可以用od 命令查看,也可以用gdb的x命令查看。 有些输出内容过多,我们可以使用 more或less命令结合管道查看,也可以使用输出重定向来查看。

例:od code.o |. more

od code.o > code.txt

汇编文件中的"."开始的语句

在汇编".s"文件中,以"."开头的行都是指导汇编器和链接器的命令。我们可以忽略这些行。

Linux和Windows的汇编格式的区别

    ATT格式和Intel格式

  • Intel代码省略了指示大小的后缀。我们看到指令mov,而不是movl。
  • Intel代码省略了寄存器名字前面的‘%‘符号。用esp,而不是%esp。
  • Intel代码用不同的方式来描述存储器中位置。例如,是‘DWORD PTR [ebp+8]‘而不是‘(ebp)‘。

不同数据汇编代码的后缀

    汇编代码指令都有一个字符后缀,表明操作数大小。

  • 后缀b代表大小为字节。例如:movb(传送字节)。
  • 后缀w代表大小为字。例如:movw(传送字)。
  • 后缀l代表大小为双字。例如:movl(传送双字)。

部分寄存器

  • esi和edi:可以用来操纵数组。
  • esp和ebp:可以用来操纵栈帧。
  • 对通用寄存器中eax,ebx,ecx,edx中和ax,al,ah等的关系

    |===============EAX===============|--32个0,4个字节,2个字,1个双字

    |======AX=======|--16个0,2个字节,1个字

    |==AH===|-----------8个0,1个字节

    |===AL==|---8个0,1个字节

    虽说EAX是32位的寄存器,但其实只是在原有的8086CPU的寄存器AX上增加了一倍的数据位数而已。故而EAX与AX根本不可能独立,二者是整体与部分的关系。

    对EAX直接赋值,若更改了低16位自然会改变了AX值,而AX又可以影响EAX整体。而AH,AL寄存器和AX之间的关系也是如此。

三种操作数类型

  • 立即数:也就是常数值。
  • 寄存器:它表示某个寄存器的内容。
  • 存储器:它根据计算出来的地址(通常称为有效地址)访问某个存储器位置。

汇编的寻址方式


类型


格式


操作数值


名称


立即数


$Imm


Imm


立即数寻址


寄存器

 
R[]


寄存器寻址


存储器


Imm


M[Imm]


绝对寻址


存储器


()


M[R[]]


间接寻址


存储器


Imm()


M[Imm+R[]]


(基址+偏移量)寻址


存储器


(,)


M[R[]+R]]


变址寻址


存储器


Imm(,)


M[lmm+R[]+R[]]


变址寻址


存储器


(,,s)


M[R[]*s]


比例变址寻址


存储器


Imm(,,s)


M[Imm+R]*s]


比例变址寻址


存储器


(,,s)


M[R[]+R[]*s]


比例变址寻址


存储器


Imm(,,s)


M[Imm+R[]+R[]*s]


比例变址寻址

数据传送指令

  • MOV:传送字节。
  • MOVS:传送符号扩展的字节。
  • MOVZ:传送零扩展的字节。

PUSH和POP

push指令的功能是把数据压入到栈上,而pop指令是弹出数据。这些指令都只是只有一个操作数——压入的数据源和弹出的数据目的。

指针就是地址,局部变量保存在寄存器中。

算术和逻辑操作指令


指令


效果


描述


leal S,D


D←&S


加载有效地址


INC D

DEC D

NEG D

NOT D


D←D+1

D←D-1

D← -D

D← ~D


加1

减1

取负

取补


ADD S , D

SUB S , D

IMUL S , D

XOR S , D

OR S , D

AND S , D


D← D+S

D← D-S

D← D*S

D← D^S

D← D|S

D← D&S


异或


SAL k,D

SHL k,D

SAR k,D

SHR k,D


D← D<<k

D← D<<k

D← D>>

D← D>>


左移

左移(等同于SAL)

算术右移(补符号位)

逻辑右移(补零)

条件码

  • CF:进位标志。最近的操作使最高位产生了进位。可以用来检查无符号操作数的溢出。
  • ZF:零标志。最近的操作得出的结果为0。
  • SF:符号标志。最近的操作得到的结果为负数。
  • OF:溢出标志。最近的操作导致一个补码溢出——正溢出或负溢出。

CMP指令根据它们的两个操作数之差来设置条件码。

TEST指令根据它们的两个操作数的与(&)来设置条件码。

CMP和SUB的区别:CMP只改变条件码,SUB不仅改变条件码还改变目的操作数。

SET指令:根据条件码的某个组合,将一个字节设为0或者1。(P125 图3-11)

跳转指令


指令


描述


jmp Label


直接跳转


jmp *Operand


间接跳转


je(jz)


相等/零


jne(jnz)


不相等/非零


js


负数


jns


非负数


jg(jnle)


大于(有符号>)


jge(jnl)


大于或等于(有符号>=)


jl(jnge)


小于(有符号<)


jle(jng)


小于或者等于(有符号<=)


ja(jnbe)


超过(无符号>)


jae(jnb)


超过或相等(无符号>=)


jb(jnae)


低于(无符号<)


jbe(jna)


低于或相等(无符号<=)

转移控制指令


指令


描述


call Label


过程调用


call *Operand


过程调用


leave


为返回准备栈


ret


从过程调用中返回

注:leave指令在16位汇编下相当于:

mov sp,bp

pop bp

在32位汇编下相当于:

mov esp,ebp

pop ebp

过程与栈

    一个过程调用包括将数据(以过程参数和返回值的形式)和控制从代码的一部分传递到另一部分。另外,它还必须在进入时为过程的局部变量分配空间,并在退出时释放这些空间。数据传递、局部变量的分配和释放都是通过操纵程序栈来实现的。

机器用栈来传递过程参数、存储返回信息、保存寄存器用于以后恢复,以及本地存储。为单个过程分配的那部分栈称为栈帧。

过程调用和返回指令


指令


描述


call Label


过程调用


call *Operand


过程调用


leave


为返回准备栈


ret


从过程调用中返回

注:call/ret; 函数返回值存在%eax中。

实验练习

实验代码:

编译后的汇编代码:

a:

pushl    %ebp

movl    %esp, %ebp

movl    8(%ebp), %eax

addl    $3, %eax

popl    %ebp

ret

r:

pushl    %ebp

movl    %esp, %ebp

pushl    8(%ebp)

call    a

addl    $4, %esp

leave

ret

main:

pushl    %ebp

movl    %esp, %ebp

pushl    $8

call    r

addl    $4, %esp

addl    $1, %eax

leave

ret

时间: 2024-12-01 03:36:15

程序的机械级表示学习记录的相关文章

程序员面试笔试宝典学习记录(三)(数据库相关知识)

关系数据库系统与文件数据库系统的区别如下: (a)关系数据库系统的主要特征是数据的结构化,而文件数据库系统是数据的非结构化. (b)关系数据库系统中,用户看到的逻辑结构是二维表,而文件数据库系统中,基本元素是文件. (c)文件数据库系统可以实现多媒体文件管理,支持C/S工作模式. acid,指数据库事务正确执行的四个基本要素的缩写.包含:原子性(atomicity),一致性(consistency),隔离性(isolation),持久性(durability). 数据查询:select sele

【程序员编程艺术】学习记录3:字符串包含问题

[程序员编程艺术]学习记录3:字符串包含问题 题目: 假设这有一个各种字母组成的字符串A,和另外一个字符串B,字符串里B的字母数相对少一些.什么方法能最快的查出所有小字符串B 里的字母在大字符串A里都有? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

【程序员编程艺术】学习记录1:左旋转字符串之指针翻转法

[程序员编程艺术]学习记录1:左旋转字符串之指针翻转法 题目:左旋转字符串 定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部,如把字符串abcdef左旋转2位得到字符串cdefab.请实现字符串左旋转的函数,要求对长度为n的字符串操作的时间复杂度为O(n),空间复杂度为O(n) 思路一.暴力移位法 //暴力移位法 void leftshiftone(char *s, int n) { char t = s[0]; for(int i = 1;i < n; i++) s[i-1]

【程序员编程艺术】学习记录2:左旋转字符串之循环移位法

[程序员编程艺术]学习记录2:左旋转字符串之循环移位法 GCD算法:(辗转相除法/欧几里得算法) gcd是求最大公约数的算法,作为TAOCP第一个算法 gcd算法流程: 首先给定两个整数m,n(m大于等于n)如果小于则直接交换再处理 ①求余数 r=m%n ②假如r=0,算法结束,n即为所求 否则,重新令m <- n, n <-r 之后循环 <<<<<<<<<<<<<<<<<<<&l

第三章程序的机器级表示 学习报告

第三章 程序的机器级表示 3.1 历史观点 Intel处理器系列俗称x86,开始时是第一代单芯片.16位微处理器之一. 每个后继处理器的设计都是后向兼容的——较早版本上编译的代码可以在较新的处理器上运行. X86 寻址方式经历三代: 1  DOS时代的平坦模式,不区分用户空间和内核空间,很不安全 2  8086的分段模式 3  IA32的带保护模式的平坦模式 3.2 程序编码 gcc -01 -o p p1.c -01 表示使用第一级优化.优化的级别与编译时间和最终产生代码的形式都有关系,一般认

程序员修炼之道学习记录之注重实效的哲学

我的源码让猫吃了 软件的熵(无序) 石头汤和煮青蛙 你的知识财产 交流

Android socket 学习记录 之 执行new socket(ip, port)程序崩溃

这段时间在学习Android的socket编程,我不是专做APP的,做的是bootloader.驱动.hal.framework这个线的,也就是系统搭建和功能优化设计.为了打通这整条线,为此学习了不少东西,今天把Android的socket学习记录一下,以防止以后会出现这样的低级错误. 我这里是在极客学院的源码基础上做的自己的一些添加和修改,学习开始不就是先会修改么,举一反三,自然就很快学会了.由于看过视频和资料后就迫不及待的按照自己的想法想做一个功能,但是遇到麻烦了,就是执行new socke

深入理解计算机系统之程序的机器级表示部分学习笔记

不论我们是在用C语言还是用JAVA或是其他的语言编程时,我们会被屏蔽了程序的机器级的实现.机器语言不需要被编译,可以直接被CPU执行,其执行速度十分  快.但是机器语言的读写性与移植性较高级语言低.高级语言被编译后便成为了汇编语言,汇编语言十分接近机器语言.之后汇编代码会转化为机器语言.虽然现代  的编译器能帮助我们将高级语言转化为汇编语言,解决了不少问题,但是对于一个严谨的程序员来说,需要做到能够阅读和理解汇编语言.我们主要围绕Intel来讲  解. 一  Intel处理器的历史演变 Inte

C程序的学习记录

以下内容是本人作为编程新手的一些学习记录,如有错误,望指出纠正. 两个变量的数值交换可以不用到中间变量,有两种方法可以做到不借助中间变量将两个变量的数值交换.第一种是通过两变量的三次加减运算完成:第二种是通过异或的方法实现. 1 #include<stdio.h> 2 3 int main(int argc,int *argv) 4 { 5 int var1 = 5; 6 int var2 = 9; 7 printf("第一种交换方式:"); 8 var1 = var1 +