iOS (Swift & Objective-C & Xcode)

汇编

2017-08-04  本文已影响92人  7b33a23272c4

单位说明

在计算机中最小的信息单位,称之为位(bit,又称比特)。 存储器中所包含存储单元的数量称为存储容量,其计量基本单位是字节(Byte。简称B)

总线 (8086处理器16bit CPU)

CPU寻址示例图

寄存器

寄存器是中央处理器内的组成部分。寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址。

通用寄存器

字和字节

8086寻址方式

物理地址 段地址 偏移地址
0x32AF1
0x32AF1 0x3200 0x0AF1
0x32AF1 0x32AF 0x0001
0x32AF1 0x32A0 0x00F1
0x32AF1 0x3000 0x2AF1

内存分段管理

段寄存器

CS和IP

JMP指令

jmp 2AE3:3 
CS: 0x2AE3
IP: 0x0003
则从内存地址0x2AE33处读取指令


jmp 3:0B16 
CS: 0x0003
IP: 0x0B16 
则从内存地址0x00B46 (CS*16+IP) 处读取指令
jmp ax  -> 执行前: ax = 1000H, CS = 2000H, IP = 0003H
           执行后: ax = 1000H, CS = 2000H, IP = 1000H

jmp bx  -> 执行前: bx = 1003H, CS = 2000H, IP = 1000H
           执行后: bx = 1003H, CS = 2000H, IP = 1003H

DS和[address]

完整的汇编

assume cs:code
code segment
    mov ax, 1122h
    mov bx, 3344h
    add ax, bx
    
    ;退出程序
    mov ah, 4ch
    int 21h
code ends
end

中断

从本质上来讲,中断是一种电信号,当设备有某种事件发生时,它就会产生中断,通过总线把电信号发送给中断控制器。如果中断的线是激活的,中断控制器就把电信号发送给处理器的某个特定引脚。处理器于是立即停止自己正在做的事,跳到中断处理程序的入口点,进行中断处理

;hello world! 字符串的输出
;寄存器关联:代码段code与代码段寄存器CS关联,
;数据段data与数据段寄存器DS关联。
assume CS:code,DS:data ;注意:assume是伪指令,在扫描编译时不翻译
 
;data数据段定义
data segment
  string db 'Hello world$' ;切忌串结束符$, string:声明,使用可去掉offset
data ends
 
;代码段定义
code segment
;程序开始
start:
  mov ax,data  ;将数据段段地址装入AX寄存器
  mov ds,ax ;将数据段段地址通过通用寄存器AX装入DS
  mov dx,offset string ;将串的段内地址装入DX, 
  mov ah,09h ;调用DOS的09H号功能,传入参数DS:DX=串地址,'$'结束字符串
  int 21h
  mov ah,4ch ;调用DOS的4CH号功能,带返回码结束,返回码存在于AL
  int 21h
code ends  ;代码段定义结束
end start  ;程序结束

push ax

pop ax

通过栈交换ax, bx内容

assume cs:code
code segment
start:
    mov ax, 1000h
    mov ss, ax
    mov sp, 0010h
    mov ax, 1122h
    mov bx, 2233h
    ;通过栈的特性交换
    push ax
    push bx
    pop ax
    pop bx
    ;exit
    mov ah, 4ch
    int 21h
code ends
end start
   

栈段

assume cs:code,ss:stack,ds:data   

;栈段(存放数据,比如高级语言中的局部变量)
stack segment
    db 20 dup(1) ;定义一个20个字节的空栈,默认值为1
stack ends  

;数据段(存放数据,比如高级语言中的全局变量)
data segment   
     db 20 dup(0)
     str db "Hello World!$"    
data ends

code segment
start:
    ;栈初始化
    mov ax, stack
    mov ss, ax
    
    ;exit
    mov ax, 0x004ch
    int 21h
code ends
end start

栈顶指针,指向0x07114内存空间


定义栈段

Loop指令

;通过loop求2的6次方的和64
assume cs:code

code segment
start:
    mov ax, 2
    mov cx, 0x05h ;设置循环次数
s:  add ax, ax
    loop s
    ; exit
    mov ah, 4ch
    int 21h
code ends
end start
            

结果: ax: 0x0040h = 64

通过loop求2的6次方的和64

Call和ret指令

Call

ret

示例1
assume cs:code,ds:data

data segment
    str db 'Hello world!$'
data ends

code segment
start:
    mov ax, data
    mov ds, ax
    ;调用打印函数
    call print
    ;exit
    mov ah, 4ch
    int 21h
    
print:
    mov dx, offset str
    mov ah, 09h
    int 21h
    ret
code ends
end start

call print 之后,将下一条指令地址(07118h-07119h)的偏移地址0008h入栈, 根据print标号指向的内存地址的偏移地址赋值给IP(0x000C),然后执行print函数


call print

print 函数结束后,调用ret,将下一条指令偏移地址出栈,赋值给IP


ret
示例2:外平栈

函数执行前后, SP不变

assume cs:code,ss:stack

stack segment
    db 20 dup(0)
stack ends
code segment
start:
    mov ax, stack
    mov ss, ax

    push 1
    push 2
    push 3
    call sum
    add sp, 6 ;外平栈操作 SP恢复为默认值0x0014
    
    push 1
    push 2
    push 3
    call sum
    add sp, 6 ;外平栈操作 SP恢复为默认值0x0014
    
    push 1
    push 2
    push 3
    call sum
    add sp, 6 ;外平栈操作 SP恢复为默认值0x0014
    
    ;exit
    mov ah, 4ch
    int 21h
    ;参数:传递两个字型参数,参数分别用bx,dx存放
    ;返回值:返回值存放在ax中    
sum:
    mov bp, sp ;sp不能加减,bp可以
    mov ax, ss:[bp+2]
    add ax, ss:[bp+4]
    add ax, ss:[bp+6]
    ret
code ends
end start
示例3:内平栈

函数执行前后, SP不变

assume cs:code,ss:stack

stack segment
    db 20 dup(0)
stack ends
code segment
start:
    mov ax, stack
    mov ss, ax
    
    push 1
    push 2
    push 3
    call sum
    
    push 1
    push 2
    push 3
    call sum
    
    push 1
    push 2
    push 3
    call sum
    
    ;exit
    mov ah, 4ch
    int 21h
    ;参数:传递两个字型参数,参数分别用bx,dx存放
    ;返回值:返回值存放在ax中    
sum:
    mov bp, sp ;sp不能加减,bp可以
    mov ax, ss:[bp+2]
    add ax, ss:[bp+4]
    add ax, ss:[bp+6]
    ret 6 ;SP恢复为默认值0x0014
code ends
end start
示例4(重要):完整函数调用过程,对bp进行现场保护

完整函数调用过程:

  1. push参数(64位cpu 任性使用寄存器)
  2. call指令调用(将下一条指令地址入栈)
  3. 保护bp寄存器,将sp赋值给bp
  4. 提升sp指针,作为局部变量空间(sp 减去值)
  5. 保护寄存器
  6. 业务逻辑
  7. 恢复寄存器
  8. 恢复sp(sp指向bp/sp 加上值)
  9. 恢复bp(pop bp)
  10. 返回(ret)
C语言:
int sum(int a, int b)
{
    int c = 1;
    int d = 2;
    return a + b + c + d;
}

sum(3,4)


汇编:
assume cs:code,ss:stack

stack segment
    db 40 dup(0)
stack ends

code segment
start:
    mov ax, stack
    mov ss, ax  
    
    ;假设初值
    mov bp, 1002h
    mov bx, 1003h
    mov cx, 1004h
    mov dx, 1005h
    
    ;执行求和函数
    push 03h ;传递参数
    push 02h ;传递参数
    call sum ;调用函数
    
    ;exit
    
    mov ah, 4ch
    int 21h
    
sum:
    push bp ;现场保护,防止多个函数调用改变bp
    mov bp, sp
    sub sp, 20 ;20字节留作局部变量
    ;保护寄存器
    push bx
    push cx
    push dx 
    
    ;*业务逻辑代码*
    
    ;申明局部变量 
    mov ss:[bp-2], 1h
    mov ss:[bp-4], 2h  
    
    ;有可能修改寄存器
    mov bx,2h
    mov cx,3h
    mov dx,4h  
    
    ;计算结果
    mov ax, [bp+4] ; bp 指向call 下条指令地址,取形参要加4
    add ax, [bp+6]
    add ax, [bp-2] ;局部变量
    add ax, [bp-4]
    
    ;sp指向寄存器保护位置
    pop dx
    pop cx
    pop bx
    
    ;清空局部变量
    mov sp,bp
    pop bp; 现场保护恢复
    ret 4 ;栈平衡
code ends
end start

调用函数前 调用函数后
SP BP BX CX DX
调用函数前 0x0028 0x1002 0x1003 0x1004 0x1005
调用函数后 0x0028 0x1002 0x1003 0x1004 0x1005
上一篇 下一篇

猜你喜欢

热点阅读