汇编语言简要记录



  • 基础:

    数制转换

    • 使用汇编语言编写的源代码,然后通过相应的汇编程序将它们转换成可执行的机器代码。这一过程被称为汇编过程

    • 普遍地说,每一种特定的汇编语言和其特定的机器语言指令集是一一对应的。

    • DB, DW, DD, DQ, DT 依次为 1, 2, 4, 8, 10

    • x86/amd64汇编指令的两大风格分别是Intel汇编与AT&T汇编,分别被Microsoft Windows/Visual C++GNU/Gas采用(Gas也可使用Intel汇编风格)

    • 项目 Intel风格(dosbox使用的是这种) AT&T风格
      操作数顺序 目标操作数在前 源操作数在前
      寄存器 原样 加%前缀
      立即数 原样 $前缀
      16进制立即数 用后缀B与H分别表示二进制与十六进制 对于16进制字母开头的要加前缀0 加前缀0x
      访问内存长度的表示 前缀BYTE PTR, WORD PTR, DWORD PTR和QWORD PTR表示字节,字,双字和四字 后缀b,w,l,q表示字节,字,双字和四字
      引用全局或静态变量var的值 [var] var
      引用全局或静态变量var的地址 var $var
      引用局部变量 需要基于栈指针(rsp)
      绝对寻址 [imm] imm
      间接寻址 [reg] (%reg)
      基址相对寻址 [reg +imm] imm(%reg)
      变址寻址 [base+index] (base,index)
      变址寻址 imm[base+index] imm(base,index)
      比例变址寻址 imm[base + index * scale ] imm(base, index, scale)
      scale只能是1,2,4,8其中的一个数字(1省略不写就是普通变址寻址)
      代码注释 单行注释用;+注释内容。例如:mov rax, rdx ;这里是注释
      注意 这里imm为立即数,base和index为寄存器,scale为伸缩量

    区分 地址 和 数

    • 举例

      DS: [1000h]; 这是一个地址, 位置是 1000h
      3000h; 这是一个数, 大小是 3000h
      
      
      • 助记符--->机器指令
      • 变量--->操作数存放地址
      • 指令前的标号--->该指令的存放地址


  • 为什么要分段(内存, 虚拟内存, 分段部件, 分页部件)

    • 历史

      • 1978年 推出 16 位 cpu8086, 内外数据线为 16 位, 地址总线为 20 位, 主存寻址 1MB
      • 1982年 推出 cpu80286, 内外数据线为 16 位, 地址总线为 24 位, 主存寻址 16MB
      • 1985年 推出32位 cpu80386, 内外数据线为 32 位, 地址总线为 32 位, 主存寻址 4GB(1MB*2^12)
    • 物理原因

      • 总线 20 位 ---> 寻址 1MB

      • 总线 32 位 ---> 寻址 4G

      • 段寄存器为 16 位 ---> 段的大小为 64K

      • 最低端 80X86 16 位虚拟机中, 内部结构是 16 位, 主线是 20 位, 为了解决这一问题:

        • 将 1MB(20 位)的主存按 64KB(16 位)分段
        • 设置四个段寄存器 CS, DS, SS, ES 保存段首址(20 位的高 16 位), 将这个 16 位(左移四位再变成 20 位)加上数据的偏移地址就得到了物理地址
        • 其中 CS--->IP, SS--->SP, 一般情况下不需要定义附加数据段, 如果必须定义, 最简单的方法是让附加数据段与数据段重合.
      • 32 位暂时没看😬



  • 寄存器

    • 数据寄存器组(可以用作 16, 8 位, 但是此时不能用作指示器, 变址寄存器?)
      • EAX 累加器
      • EBX 基址寄存器
      • ECX 计数寄存器
      • EDX 数据寄存器
    • 指示器变址寄存器组(存放偏移地址, 用作指示器或者变址寄存器, 可用作 16, 不能用作 😎
      • ESI 源操作数指示器
      • EDI 目的操作数指示器
      • EBP 基址寄存器
      • ESP 专用堆栈指示器, 一般不做数据寄存器
    • 段寄存器
      • CS 代码段寄存器
      • SS
      • DS
      • ES, FS, GS

    标志寄存器

    • zf: 零标志位, 相关指令执行后结果为 0 则 zf=1, 否则 0
      mov ax,1
      sub ax,1
    • pf: 奇偶标志位, 结果中 1 为偶数 pf=1, 否则 0
    • sf: 符号标志位, 结果为负, sf=1, 否则为 0
    • cf: 进位标志位, 在进行无符号数运算的时候,CF记录了运算结果的最高有效位向更高有效位向更高位的进位值/借位值,产生进位或向更高位借位都会使CF=1
    • of: 溢出标志位, 超出机器所能表示的范围 of=1, 否则 0


  • 子程序

    • NEAR FAR
      • NEAR 可省略
      • FAR
      • 区别主要在于 NEAR 只是把 ip 入栈, 把 ea 赋值给 ip, FAR 在 NEAR 的基础上还要把 CS 入栈(最先入 cs, 再入 ip)
    • RET 根据 NEAR 还是 FAR 出栈
    • 传递参数
      • 寄存器法
      • 约定单元法
      • 堆栈法

    模块化处理

    F2T10.ASM
    NAME F2T10
    PUBLIC F2T10; 这里的 public 指明了 F2T10 是可以被其他模块调用的, 该语句可以放在任何地方
    DATA  SEGMENT  USE16 PARA    PUBLIC 'DATA'
    ;段名 segment 使用类型 定位方式 组合方式 '类别'
    ;定位方式中para为默认, 定义段在什么样的起始边界开始
    ;类别的作用是生成 exe 的时候进行分组(分配空间)
    ;组合方式连在一起, public 同类别段会放在一起
    ...
    DATA ENDS
    
    CODE SEGMENT USE16 PARA PUBLIC 'CODE'
    ASSUME CS:CODE, DS:DATA
    F2T10 PROC
    ...
    F2T10 ENDP
    CODE ENDS
    END
    -----------------------------------------
    MAIN.ASM
    ;以上是一个子模块, 下面的是主模块
    NAME MAIN
    EXTRN F2T10:NEAR; 这里指明 F2T10 是外部模块的, 例如子程序, 如果两个代码块的类别名相同, 相当于在一个段里, 用 EXTRN F2R10:NEAR, 否则用 far
    IF1 
    ;IF XXX ... ELSE ... ENDIF 如果条件成立就执行块中的语句, 其中if 有几个固定搭配
    	INCLUDE MACRO.LIB
    ENDIF
    .386
    DATA SEGMENT USE16 PARA PUBLIC 'DATA'
    ...
    DATA ENDS
    
    CODE SEGMENT USE16 PARA PUBLIC 'CODE'
    ASSUME CS:CODE, DS:DATA
    START:...
    CODE ENDS
    START END
    
    masm main.asm
    masm F2T10.asm
    然后执行:LINK MAIN+F2T10;生成 main.exe
    


  • 指令合集

    MOV OPD, OPS; MOVE DEST SRC
    
    XLAT; TRANSLATE ([BX+AL])->AL 
    
    LEA OPD, OPS; LOAD EFFECTIVE ADDRESS 立即寻址 等价于 MOV OPD, OFFSET OPS, 其中 OPD 必须是 16/32 位寄存器
    
    ;标志位?
    
    NEG OPD; NEGTIVE 将 OPD 的每一位取反最后加一, 包括符号位, 得到结论: 负数"取补码"得到绝对值
    
    IMUL OPD, OPS;INTEGER MULTIPLICATION (OPD)*(OPS)->OPD
    IMUL OPD, OPS, N; (OPS)*N->OPD
    IMUL OPS; 
    (AL)*(OPS)->AX
    (AX)*(OPS)->DX, AX
    (EAX)*(OPS)->EDX, EAX
    MUL
    
    DIV OPS;
    (AX)/(OPS)->AL 商, AH 余数
    (DX, AX)/(OPS)->AX 商, AH 余数
    (EDX, EAX)/(OPS)->EAX商, EDX余数
    IDIV
    
    NOT OPD; 取反
    AND OPD, OPS; 逻辑与
    TEST OPD, OPS
    常见用法: TEST ECX, ECX 判断 ecx 是否为空, 如果为空则 zf=1
    总结: test 是逻辑与运算, cmp 是 sub 运算, cmp a1, a2 执行操作 a1-a2
    XOR OPD, OPS; 异或
    
    SAL OPD, N 或者 SHL OPD, N; ARITHMATIC SHIFT LEFT, SHIFT LEFT 左移, 逻辑算数都一样
    SHR OPD, N; 逻辑右移, 加 0
    SAR OPD, N; 算数右移, 加符号位
    
    ROL OPD, N; 循环左移
    ROR OPD, N
    RCL OPD, N; ROTATE LEFT WITH CARRY 带进位循环左移
    RCR OPD, N
    
    ABOVE, BELOW 无符号, GREATER LESS 有符号
    JA; JUMP WHEN ABOVE
    JNA; JUMP WHEN NOT ABOVE
    JAE; JUMP WHEN ABOVE OR EQUAL
    JNAE; JUMP WHEN NOT ABOVE OR EQUAL 不大于, 且不等于
    
    JB; JUMP WHEN BELOW
    JNB; JUMP WHEN NOT BELOW
    JBE; JUMP WHEN BELOW OR EQUAL
    JNBE; 
    
    JG; JUMP WHEN GREATER
    JNG
    JGE; JUMP WHEN GREATER OR EQUAL
    JNGE; JUMP WHEN NOT GREATER OR EQUAL 
    
    JL; JUMP WHEN LESS
    JNL; JUMP WHEN NOT LESS
    JLE
    JNLE; JUMP WHEN NOT LESS OR EQUAL
    
    JE; JUMP WHEN EQUAL
    JZ; JUMP WHEN HAS ZERO FLAG JZ=JE
    JNE
    JNZ
    JO; JUMP WHEN HAS OVERFLOW FLAG
    JC; JUMP WHEN HAS CARRY FLAG
    
    ;pf: 奇偶标志位, 结果中 1 为偶数 pf=1, 否则 0
    JP; JUMP WHEN HAS PARITY(奇偶) FLAG
    JPO; JUMP WHEN PARITY FLAG IS ODD, JP = JPE
    JPE; JUMP WHEN PARITY FLAG IS EVEN, JNP = JPO
    JS; JUMP WHEN HAS SIGN FLAG
    
    
    INT; INTERRUPT
    
    DW; DEFINE WORD
    
    PROC; PROCEDURE
    
    ENDS; END SEGMENT
    
    PTR; POINTER
    
    MOVSX; EXTENDED MOVE WITH SIGN DATA
    MOVZX; EXTENDED MOVE WITH ZERO DATA
    
    
    ***********************
    
    
    PUSH OPS; SP=SP-1
    
    POP OPD; SP=SP+1
    
    DIV;https://blog.csdn.net/loovejava/article/details/7044242
    
    IMUL OPD, OPS; 有符号数乘法
    IMUL OPD, OPS, N; OPS*N->OPD
    IMUL OPS; AL*OPS->AX 字节
    					AX*OPS->DX,AX 字
    					EAX*OPS->EDX,EAX 双字
    MUL;无符号乘法,用法同上
    
    ADD AX,10;把 ax 加上 10 再存到 ax 里
    
    SUB
    
    LOOP 标号
    
    逻辑移位, 总是用 0 补充
    SHL EDX, 7;EDX 左移 7 位
    shr ;右移
    
    算数移位, 用符号位补充
    sar;右移
    
    CBW ;将 AL 中的符号扩展到 AH 里
    
    ;意义    无符号比较     有符号比较
    >        JA, JNBE     JG, JNLE
    >=			 JAE, JNB			JNC, JGE, JNL
    <				 JB, JNAE			JC, JL, JN, JNGE
    <				 JBE, JNA			JLE, JNG
    
    CMP BYTE PTR[SI],"#" ;ptr前面的类型有byte(字节)、word(字)、dword(双字)、qword(四字)、tbyte(十字节)、far(远类型)和near(近类型)
    
    LEA 
    lea指令
    load effective address, 加载有效地址,可以将有效地址传送到指定的的寄存器。指令形式是从存储器读数据到寄存器, 效果是将存储器的有效地址写入到目的操作数, 简单说, 就是C语言中的”&”.
    mov指令
    在CPU内或CPU和存储器之间传送字或字节,它传送的信息可以从寄存器到寄存器,立即数到寄存器,立即数到存储单元,从存储单元到寄存器,从寄存器到存储单元,从寄存器或存储单元到除CS外的段寄存器(注意立即数不能直接送段寄存器),从段寄存器到寄存器或存储单元。
    但是注意
    (1) MOV指令中的源操作数绝对不能是立即数和代码段CS寄存器;
    (2) MOV指令中绝对不允许在两个存储单元之间直接传送数据;
    (3) MOV指令中绝对不允许在两个段寄存器之间直接传送数据;
    (4) MOV指令不会影响标志位
    使用[]区别
    第二操作数加不加中括号[]的区别就是:
    lea对变量没有影响是取地址,对寄存器来说加[]时取值,第二操作数不加[]非法
    mov对变量来说没有影响是取值,对寄存器来说是加[]时取地址,第二操作数不加[]是取值
    

登录后回复
 

Copyright © 2018 bbs.dian.org.cn All rights reserved.

与 Dian 的连接断开,我们正在尝试重连,请耐心等待