【汇编】汇编语言初识&lldb常用指令

要想掌握一门语言,就要探其本质,知晓其中的内存和指针变化,这时候汇编就显得格外重要。

汇编语言的种类

  • 汇编语言的种类

    • 8086汇编(16bit)
    • x86汇编(32bit)
    • x64汇编(64bit)
    • ARM汇编(嵌入式,移动设备)
    • ……
  • x86、x64汇编根据编译器的不同,有2种书写格式

    • Intel:Windows派系
    • AT&T:Unix派系(例,iOS模拟器)

常见汇编指令

寄存器与内存

  • CPU组成
    • 寄存器(信息存储)
    • 运算器(信息处理)
    • 控制器

通常,CPU会先将内存中的数据存储到寄存器中,然后再对寄存器中的数据进行运算

假设内存中有块红色内存空间的值是3,现在先把它的值+1,并将结果存储到绿色内存空间

图解:

代码:

1
2
var num = 3
var num1 = num + 1

寄存器

64位AT&T混编中常用的寄存器有16种

  • %rax、%rbx、%rcx、%rdx、%rsi、%rdi、%rbp、%rsp
  • %r8、%r9、%r10、%r11、%r12、%r13、%r14、%r15

寄存器的具体用途

  • %rax常作为函数返回值使用
  • %rdi、%rsi、%rdx、%rcx、%r8、%r9等寄存器常用于存放函数参数
  • %rsp、%rbp用于栈操作

movq -0x18(%rbp), %rax
意思:根据内存地址找到对应存储空间的数据取出来赋值给%rax

leaq -0x18(%rbp), %rax
意思:直接将%rbp-0x18地址值赋值给%rax

  • calljmp区别

    • jmp 0x000a1841,跳转到函数内存地址0x000a1841执行相关指令,跳转后不返回
    • call 0x000a1841,也是跳转,和ret配合使用,但跳转0x000a1841函数执行完成后会返回继续执行之前的代码
  • call *%rdx,意思是跳转到寄存器里面的地址

  • 混编指令后面的字符是什么意思?(例:movqleaw

    • 代表操作数长度(具体参照上图)

r 开头的是64位(8字节)的寄存器(CPU是64位的)

e 开头的是32位(4字节)的寄存器(CPU是32位的)

axbxcx 开头的是16位(2字节)的寄存器(CPU是16位的)

ahalbhbl 开头的是8位(1字节)的寄存器(CPU是8位的)
h 意思是high,代表占用高位;l 意思是low,代表占用低位

思考:高位寄存器怎么兼容低位寄存器?

  • 64位寄存器需要兼容32位,32位需要兼容16位
  • 如果使用的是64位(630),把内存的低位给32位用(310),一直往后推理

lldb常用指令

  • 读取寄存器的值:

    • register read/格式
    • register read/x
    • 例:register read rax
    • 在lldb中不需要加%,在汇编语言中才需要加
    • 如果只输入register read,就会把所有寄存器的值打印出来
  • 修改寄存器的值

    • register write 寄存器名称 数值
    • register write $rax 0
  • 读取内存中的值

    • x/数量-格式-字节大小 内存地址
    • x/3xw 0x0000000100008200 意思:读取3组16进制形式展示的数据,每组4个字节
  • 修改内存中的值

    • memory write 内存地址 数值
    • memory write 0x0000000100008200 10
  • 格式

    • x是16进制
    • f是浮点
    • d是十进制
  • 字节大小

    • b - byte 1字节
    • h - half word 2字节
    • w - word 4字节
    • g - giant word 8字节
  • expression 表达式

    • 可以简写:expr 表达式
    • expression $rax
    • expression $rax = 1
    • expression 高级语言代码
  • po 表达式

  • print 表达式

  • po/x $rax

更多指令参考 help expression

示例代码

1
2
3
4
5
6
func test() {
let a = 3
let b = a + 1
print(b) // 此处打断点进入混编
}
test()

指令展示

代码调试运行指令

  • thread step-over

    • 简写:nextn
    • 单步运行,把子函数当做整体一步执行(源码级别)
  • thread step-in

    • 简写:steps
    • 单步运行,遇到子函数会进入子函数(源码级别)
  • thread step-inst-over

    • 简写:nextini
    • 单步运行,把子函数当做整体一步执行(汇编级别)
  • thread step-inst

    • 简写:stepisi
    • 单步运行,遇到子函数会进入子函数(汇编级别)
  • thread step-out

    • 简写:finish
    • 直接执行完当前函数的所有代码,返回到上一个函数(遇到断点会卡主)

看到上面的指令名称,应该常用Xcode开发的同学会很熟悉,没错,就是Xcode上面的断点调试功能

补充:
xorl - 按位异或

$ - 立即数