汇编与寄存器
Wednesday, October 26, 2022
本文共2051字
5分钟阅读时长
⚠️本文是作者P3troL1er原创,首发于https://peterliuzhi.top/principle/%E6%B1%87%E7%BC%96%E4%B8%8E%E5%AF%84%E5%AD%98%E5%99%A8/。商业转载请联系作者获得授权,非商业转载请注明出处!
Kindness is the language which the deaf can hear and the blind can see.
— Mark Twain
寄存器
在16位系统中(8086CPU)
数据寄存器
用于暂存数据的寄存器有AX、BX、CX、DX,这些寄存器可以起到暂存16位的数据的作用。每一个又可以分成高八位和低八位,如AX寄存器,高八位为AH,低八位为AL,将超出八位的数据存入AH或AL不会自动将数据填入AX的剩下空间,而是会溢出,产生数据丢失
- 寄存器AX和AL通常称为累加器(Accumulator),用累加器进行的加减乘除耗时更少
- 寄存器BX称为基地址寄存器(Base Register),可作为存储器指针来使用
- 寄存器CX称为计数寄存器(Count Register)。在循环和字符串操作时,要用它来控制循环次数(循环的次数保存在CX中,每循环一次CX就减一,直至0循环停止)
- 寄存器DX称为数据寄存器(Data Register)。在进行乘、除运算时,它可作为默认的操作数参与运算,也可用于存放I/O的端口地址
变址寄存器
SI和DI称为变址寄存器,用于存放存储单元在段内的偏移量,SI储存源地址(source index),DI储存目的地址(destination index)
指针寄存器
BP、SP称为指针寄存器,SP是堆栈指针(stack pointer),存放栈顶地址;BP是基址指针(base pointer),存放堆栈基址偏移,相当于为最开始的SP做备份(见上节RBP和RSP的讲解)
段寄存器
CS、DS、SS、ES被称为段寄存器,用于储存段地址,需要和偏移量一起使用才能查找到内存中的数据。
- CS为代码段(code segment),和IP寄存器一起使用,用于确定下一条指令的地址
- DS为数据段(stack segment),用于存储数据所在的段地址,和诸如[0]一类的表达一起使用,如果没有特别说明,[0]==DS:[0]
- SS为堆栈段(stack segment),和SP寄存器一起使用,用于确定堆栈的位置,长期指向栈顶
- ES为扩展段(extend segment),为扩展的段寄存器
指针指令寄存器
IP被称作指针指令寄存器,储存相对于段寄存器CS的偏移量,在内存中找到CS:IP处的指令并执行
在32位系统中(i386)
在AX、BX、CX、DX等前面加E,变成了EAX、EBX、ECX、EDX等,而原本的AX、BX、CX、DX等成为了其低16位,而存取它的高十六位可以通过移位操作进行(向左移16位),或者通过bswap EAX
进行(交换EAX的高、低位)
在16位CPU中,AX、BX、CX和DX不能作为基址和变址寄存器来存放存储单元的地址,但在32位CPU中,其32位寄存器EAX、EBX、ECX和EDX不仅可传送数据、暂存数据保存算术逻辑运算结果,而且也可作为指针寄存器,所以,这些32位寄存器更具有通用性
在64位系统中(amd64)
将32位中的E前缀改为了R前缀,而原本32位中的名称用来代指64位中寄存器的低位,同时64位系统增加了8个通用寄存器,命名为R8~R15,在其后加上d,w,b指定长度(d最长,b最短)
因此64位系统中的寄存器比32位要多8个
✨ 32位系统中,函数的传递参数保存在栈帧中,而64位系统保存在寄存器中,分别用RDI,RSI,RDX,RCX,R8,R9作为第1-6个参数,用RAX保存返回值
汇编
系统如何执行汇编代码
当我们执行一个exe文件时,系统会将这个exe文件载入内存,并且将(R\E)CS:(R\E)IP指向这块内存的最低地址,每执行一句IP就自动增加(长度不固定),而所要执行的这一段代码在汇编内称为代码段。
同时,exe文件还会有它的栈段和数据段,这两段地址在内存中用汇编指令dw
(define word)声明,dw 0
就是声明一个为0的字(两个字节),dw 0,0
就是声明两个字
data segment
dw 0123h, 0456h, 0789h, 0abch, 0defh, 0fedh, 0cbah, 0987h
data ends
stack segment
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
stack ends
将对应指针寄存器指向对应段
我们的栈、数据、代码在哪里完全取决于对应的段寄存器和指针寄存器、指针指令寄存器指向哪里
因此,我们需要改变对应寄存器的值
代码
我们需要设置CS:IP,使其指向代码被载入的内存处
在汇编中,只需要在需要执行的代码前加上start:
,最后end start
即可
code segment
start:
mov ax, stack
mov ss, ax
mov sp, 100h ;初始化栈指针
mov ax, data
mov ds,ax ;初始化内存指针
code ends
end start
栈
需要将SS指向栈段,并设置SP指向栈底(一开始栈为空)
mov ax, stack
mov ss, ax
mov sp, 100h ;初始化栈指针
数据
将DS指向数据段,就可以用[0]
式的表达式存取数据了
mov ax, data
mov ds,ax ;初始化内存指针
PUSH指令和POP指令
PUSH指令和POP指令均不会变更原来的数据,而是变更目的地的数据。
push ds:[0]
就是把数据段中ds:[0]
处的数据推入栈中,相当于mov ss:sp ds:[0]
pop ds:[0]
就是把栈顶的数据弹入ds:[0]
中,相当于mov ds:[0] ss:sp
扫码阅读此文章
点击按钮复制分享信息
点击订阅