zoukankan      html  css  js  c++  java
  • Assembly

    不仅仅是汇编

    CPU中的"内存"--寄存器

    常用寄存器

    • AX: accumulator, 累加寄存器
    • CX: counter, 计数寄存器
    • DX: data, 数据寄存器
    • BX: base, 基址寄存器
    • SP: stack pointer, 栈指针寄存器
    • BP: base pointer, 基址指针寄存器
    • SI: source index, 源地址寄存器
    • DI: destination index, 目的变址寄存器

    以上的寄存器都是16位(2个字节)的寄存器

    在[A-D]X寄存器中, 每一个寄存器都是由两个8位寄存器组成的

    AX: AH + AL

    BX: BH + BL

    CX: CH + CL

    DX: DH + DL

    其中H表示High, L表示Low, 左高右低是内存中地址的分布形式, 而X是eXtend中的X, 表示扩展, 因为16位寄存器确实是8位寄存器的扩展,
    但是剩下的四个寄存去就没有High和Low之分了, 如果我们想要获取SP该16位寄存器中低8位的值, 需要将SP中的值MOV到AX之类的寄存器中, 在通过访问AL寄存器获取,
    也许你会注意到, 为什么不直接放到AL中呢? 这是因为MOV指令的作用, 因为MOV指令操作的目标源和数据源需要时大小相同的容器(在C语言中就是变量, 其实CPU中的寄存器可以为C语言中的变量, 也就是容器)

    扩展寄存器

    • EAX
    • ECX
    • EDX
    • EBX
    • ...
      通过名字我们可以判断出来, 他们与我们上面提到的常用寄存器中的AX等, 就是多了E, 其实这里的E就是从Extend中提取出来的, 表示对16位寄存器的再扩展, 成为了32位, 同上面AX与AL的关系
      一样, AX是含在EAX中的
    • 还是提一下, 任何时刻CPU执行的指令的地址在CS:IP表示的地址上, 通过公式计算可以得出对应的物理地址

    段寄存器

    这里不展开讲了, 一般段寄存器的名称是以S结尾的, 表示Sgement(段)

    汇编语言

    nasm命令行工具的使用

    • nasm -o
    • ndisasm: 反汇编工具

    汇编语言的指令

    • NASM中所有的标签和变量都是地址, 而使用了[]表示其该地址中的值
    • DB: data byte --> 向当前的地址中的一个字节slot中传入值 usage: DB 8 注意: DB "Hello world!" 也是对的, DB命令会自动将每一个字符添加到指定的位置
    • DW: data word --> 向当前地址中的两个字节slot传入值, 就是比DB多了字节数而已, 其他性质一样 usage: DW 88888
    • DD: double word --> 向当前地址中的四个字节slot传入值, 就是比DW多了字节数而已, 其他性质一样 usage: DD 88888 789798
    • RESB: reserve byte --> 指定空余多少个连续的字节, 填充的值为0 usage: RESB 100 意思是在当前位置开始空出100个字节, 并将每一个字节的值填充为0, 执行完该指令之后, 我们程序的指令也在100字节之后了, 但是在NSAM中使用不来, 替代他的是times # db 0
    • ORG: original --> 指定了程序开始的地址, 该指令后面跟的值是在特定范围的值, 否则会对系统造成破坏 usage: ORG 0x7c00
    • JMP: jump --> 类似于C语言中的goto usage: JMP entry: 其中entry:是一个标签, 实质上就是一个地址, 使用JMP让CPU其对应的地址找指令运行

    JMP指令还可以修改CS和IP这两个寄存器中的值, CS和IP中的值不能通过MOV指令实现, 因为CPU没有对应的指令, 格式: JMP 234H:222H, CS的值为234H, IP的值为222H

    JMP 段地址:偏移地址

    • MOV: move --> 类似于C语言中的赋值语句 usage: MOV SS, AX 等同于SS = AX, 注意如果两边是寄存器的话, 需要保证寄存器是同位数的
    • ADD: add --> 类似C语言中的加法赋值 usage: ADD SS, AX 等同于SS = SS + AX
    • **"("变量**: 在不同的情况下有不同的意思, 一般表示当前程序所在的内存地址, 而)$表示的一个section的地址
    • []中括号: 中括号锁定地址, MOV BYTE [123] SI 意思是找到地址为123的那个字节的slot, 将SI里面的值赋给那个字节, 同样MOV [BX] AX是找到BX寄存器中存放的值, 并根据该值找到地址编号为该值的slot, 将AX中的值赋给他, 注意: []中可以是数字, 可以是该有B或者I的寄存器(SI, BX, BH, BL, SP, DI等), 但是不可以是其他的了(AX, CX, DX, SS)
    • ORG 0x7c00: 一般出现在GRUB等bootloader中的第一行, 该指令告诉CPU将该程序加载到内存的0x7c00地址上, 并且ORG后面的值只能是一些固定的时, 在0x7c00地址之前的内存存放的是BIOS, 所以不能将bootloader加载到0x7c00之前
    • EQU: 用来为标识符定义一个整型常量,它的作用类似C语言中的#define
    • TIMES 510-((-)$) DB 0: 该指令指令经常出现在MBR中, 目的是为了除了最后的标志位0x55AA, 之前的填充为0

    NSAM中的宏定义

    • 类似于C语言中的宏定义, 不过使用的是%号, 其他都是一样的: %include, %ifndef, %define, %ifdef,
    • 使用带有参数的宏定义
    %macro macroname #(表示参数的个数)
    mov [%1] ax         ; %1表示第一个参数, 以此类推, %2, %3
    
    %endmarco
    

    练习

    • 计算2的4次方

    MOV al, 2

    ADD al, al

    ADD al, al

    ADD al, al

    实模式下CPU如何将线性地址转换为物理地址

    • 公式: 段地址(基地址) < 1 + 偏移地址
    • 在实模式下的地址如0x00123abc, 该线性地址是由段地址(这里内存并没有分段, 而是CPU为了方便管理内存采用段的机制)和偏移地址组成的, 0012为段地址, 3abc为偏移地址
    • 偏移地址的取值范围取决于CPU的寻址方位, 也就是地址总线的宽度
    • CPU访问内存时, 必须指定地址, 在8086CPU中, 采用内部段地址和内部偏移地址, 在内部加法器中通过公式计算出最终的物理地址
    • CPU中可以通过不同的段地址和偏移地址计算出同一个物理地址, 数学解方程知识

    CPU是如何判断01代码是指令还是数据的

    • 我们知道不管是指令还是数据, 在计算机的层面上都是01的代码, CPU都会将其当做指令, 有时将其当做数据, CPU是如何办到的呢?

    • 其实根据我们上一部分的知识, 通过CS:IP(段地址:偏移地址), CS < 1 + IP 得出的物理地址中的内容会被当做指令, 而没有被计算到的就会被当做数据, 每执行一次指令, IP(指令指针寄存器)中的值就会增加, 加上的值就是上一次读取的指令加数据的长度(以byte为单位), 目的是计算出下一个指令的地址

    • CPU执行的指令取决于CS:IP, 如果我们希望CPU执行我们的代码, 可以使用JMP #:#执行我们的代码段

    • 8086CPU是不允许直接使用MOV指令将数据复制给段寄存器中的. 要从一个空间复制到段寄存器中

    • CPU读指令设置CS:IP

    • CPU读数据设置DS, [address]

  • 相关阅读:
    Windows编程的Notification和Message
    static局部变量的默认初始化规则
    Windows消息的wParam和lParam及一些函数类似参数的一些用法简记
    阅读与检索
    多线程编程的几个关键点
    MSDN使用之菜单索引
    从不同角度简单阐述消息机制
    Windows程序中什么事件发生时,窗口过程会收到一条WM_SIZE消息
    三色二叉树——树形dp
    2020数学网课知识点总结
  • 原文地址:https://www.cnblogs.com/megachen/p/9555990.html
Copyright © 2011-2022 走看看