8086汇编语言
经过我这几年的工作,发现不学点底层的知识感觉心里很慌……
语法格式&关键字说明:
1.mov ds:[0h],ax 如果你不写段地址,段地址的默认地址就是数据地址;mov [0h],ax 如果你想访问数据段里的某一个内容,你可以这样写;默认前面就是ds:
2.寄存器是寄存器,内存是内存;寄存器访问本来就快,它是在CPU内部
3.把数据放放到数据段,与放到全局变量是一样的;把返回值放到ax寄存器中;ax是16位能用寄存器;eax是32位的寄存器;rax是64位的寄存器;
4.word ptr 中的ptr指的是pointer;可以用寄存器,全局变量来传参;
5.ios 里面的传参是把参数放先放到寄存器中,寄存器不够用了,再放到栈里面,因为寄存器快
6.16位的cpu 栈一定会操作两个字节的;
7.bp是辅助栈使用的;不能直接使用sp+2 ,可以使用bp+2
8.在以前的认知中局部变量与参数 在函数调用完毕之后会自动消毁、销毁就是变成垃圾内存了;C语言里面的销毁是占用的内存变成垃圾内存了,不管那个内存了,以后别人要用的话可以拿去去用;这就相当于内存被释放了;不是内存被迫害坏;
9.函数调用前与函数调用后栈应该是一样的;add esp ,8 做了栈平衡
10.; 打印字符串
print:
; ds:dx告知字符串地址
mov dx, offset string
mov ah, 9h
int 21h
ret
函数的局部变量:
1.局部变量不是你要多少个就分配多少个内存,而是一次性分配一定的空间,分配多少个由我们来定,局部变量是在栈区不在数据区,数据区一般是存放全部变量、静态变量、常量;
2.先把sp的值赋值给bp mov bp,sp 然后再减10 , sub sp,10;如果sp不减10可能会被覆盖,只要sp指针一站在sp-10处,sp-10前面的空间别人就碰不了了,我们一调用call ,就会调用push操作把下一条要执行的执令入栈;如果局部变量往栈里面放数据直接用内存指令就好了;bp+8是参数 bp-8是局部变量;局部变量是夹在bp与sp之间
3.ax就是拿来给你赋值的,与函数返回值的,不用会保护,你保护是没有用的,ax是给别人用的;保护就要保护ax以外你要用的寄存器
4.寄存器是哪个函数都能用的,所以要保护一下si、di、dx、cx,保护你用到的寄存器
5.汇编里面是不允许内存对内存,一定要通过寄存器
函数的调用流程一:
; 1.push 参数
; 2.push 函数的返回地址
; 3.push bp (保留bp之前的值,方便以后恢复)
; 4.mov bp, sp (保留sp之前的值,方便以后恢复)
; 5.sub sp,空间大小 (分配空间给局部变量)
; 6.保护可能要用到的寄存器
; 7.使用CC(int 3)填充局部变量的空间
; 8.--------执行业务逻辑--------
; 9.恢复寄存器之前的值
; 10.mov sp, bp (恢复sp之前的值)
; 11.pop bp (恢复bp之前的值)
; 12.ret (将函数的返回地址出栈,执行下一条指令)
; 13.恢复栈平衡 (add sp,参数所占的空间)
下面是函数调用代码
assume ss:stack ds:data cs:code
stack segment
db 60 dup(0)
stack ends
data segment
db 20 dup(0)
data ends
code segment
start:
mov ax,stack
mov ss,ax
mov ax,data
mov ds,ax
push 1122h ;can shu
push 3344h ;can shu
call sum
mov ax,4c00h
int 21h ;int 是interrupt 的缩写
sum:
push bp
mov bp,sp
sub sp,10
push si
push di
push dx
mov ax,0cccch
mov bx,ss
mov es,bx
mov di,bp
sub di,10
mov cx,5
rep stosw
;=======函数内部的业务逻辑 begin =====
mov word ptr ss:[bp-2],5566h ;局部变量
mov word ptr ss:[bp-4],6677h ;局部变量
mov ax,ss:[bp-2]
add ax,ss:[bp-4]
mov ss:[bp-6],ax
mov ax,ss:[bp+4]
add ax,ss:[bp+6]
add ax,ss:[bp-6]
;=======end =====
pop dx
pop di
pop si
push 2
push 1
call minus
mov sp, bp
pop bp
ret 4 ;内平栈
minus:
push bp
mov bp,sp
sub sp,10
push si
push di
push dx
mov ax,0cccch
mov bx,ss
mov es,bx
mov di,bp
sub di,10
mov cx,5
rep stosw
mov word ptr ss:[bp-2],3
mov word ptr ss:[bp-4],4
mov ax,ss:[bp+6]
sub ax,ss:[bp+4]
mov ax,ss:[bp-4]
sub ax,ss:[bp-2]
pop dx
pop di
pop si
mov sp,bp
pop bp
ret 4 ;内平栈
code ends
end start
局部变量的填充:
1.windows平台的局部变量填充用的是cc,为什么要填充那?防止程序异常的时候,比如说用户做了违法的操作(这个应用不允许的一些操作)cs:ip; 如果牵扯到内存copy的时候就用到es:di了,左边的内存拷贝到右边的内存一般会用到es:di ;32位它所有段都是一样的,es,ss,ds都是一样的大家公用一个段不像8086两个16位合成一个20位段地址:偏移地址