汇编窥探Swift底层(一):汇编基础

汇编基础

一、程序的本质

1. 程序的执行过程

如下图所示,执行软件的时候,会将软件从硬盘装载到内存中,然后由CPU控制内存读与写,同时也会控制计算机的其他设备进行响应

软件执行过程
2. CPU

如下图所示,CPU包括寄存器、运算器、控制器,寄存器负责信息存储,运算器负责信息处理,控制器负责分析指令并发出相应的控制信号

CPU

二、寄存器和内存

  • 在软件执行过程中,CPU一般会将内存中的数据放到寄存器中,在对寄存器的数据进行运算,如下图的例子
寄存器和内存
  • 假设内存中有块红色的内存空间存放着3,现在想,把3加1,并将结果存放到蓝色内存空间中,让我们来看看CPU是怎么做的:

    • (1) . 首先CPU会将红色的内存中的值放到寄存器RAX中,对应的汇编语句是这样的:movq 红色空间地址,%rax

    • (2) . 然后让rax寄存器与1相加,对应的汇编语句是这样的:addq $0x1,%rax

    • (3) . 最后将值赋值给蓝色内存空间,对应的汇编语句是这样的:movq %rax,蓝色内存空间的地址

      (PS:汇编代码看不懂没关系,学完下面的就会了,一会可以回过头来再看看)

三、编程语言的发展

  • 最开始是机器语言,由0和1构成

  • 为了方便记忆,人们用符号代替了0和1,这就是汇编语言

  • 为了更接近人类自然语言,又发明了高级语言来代表符号,例如C、C++、Python、JAVA、OC、Swift、JS等等

  • 举个例子,如果我们想将寄存器bx的值放到寄存器ax中,用三种语言表示如下,是不是感觉到越来越容易阅读了呢

    • (1) . 机器语言:10001000100010001

    • (2) . 汇编语言:movw %bx,%ax

    • (3) . 高级语言:ax = bx;

  • 本例子中高级语言执行过程,如下图所示,从高级语言编译成汇编,再编译成机器语言才能被计算机所执行


    高级语言执行过程

总结

  • 汇编语言和机器语言一一对应,从汇编语言可以编译成机器语言,从机器语言也可以反编译成汇编语言,是一对一的关系

  • 高级语言可以通过编译得到汇编语言,但是汇编语言几乎不可能反编译成高级语言,因为这是一对多的关系,多个高级语言有可能编译成同一条汇编语言。

  • 汇编语言的种类非常多,例如8086汇编、x86汇编、x64汇编等等,汇编语言大部分都非常相似,学会一种,其他的自然也能看懂了 。在iOS领域,最主要的汇编语言就两种:AT&T汇编对应着iOS模拟器ARM汇编对应着iOS真机,以下重点讲述AT&T汇编 。

四、常见汇编指令

    1. AT&T汇编中有16个常见的寄存器rax、rbx、rcx、rdx、rsi、rdi、rbp、rsp ; r8、r9、r10、r11、r12、r13、r14、r15
    1. 寄存器是CPU内部存放数据的地方,常见的用途如下:
    • 1>. rax、rdx寄存器中经常存放函数的返回值

    • 2>. rdi、rsi、rdx、rcx、r8、r9等寄存器经常用于存放函数的参数

    • 3>. rsp、rbp经常用于栈操作

    • 4>. rip一般存放指令指针,存储着CPU下一条要执行的指令的地址

    1. 下图是两种汇编语言的常用指令,格式非常相似,大家学会一种,另一种自然也就懂了,下面我来详细解释一下这张图的意思
常见汇编指令
  • 1>. 第一行是寄存器名称的命名规范,在AT&T中需要加上%,在Intel中不需要加,rax就代表寄存器的名称

  • 2>. 第二行是操作顺序,AT&T中,是将左边的rax中的值赋值给右边rdx中;Intel中,是将右边的值赋值给左边,两者顺序不同而已。

  • 3>. 第三行是常数的赋值,将3赋值给寄存器,AT&T是把3放到左边,Intel是把3放到右边

  • 4>. 第四行是movq $0xa,0x1ff7(%rip),将0xa赋值给地址为rip+0x1ff7的内存空间中,在AT&T中,内存地址的加法是用0x1ff7(%rip)表示,意思是将rip中存放的内存地址与0x1ff7相加;在Intel中的写法为[rip+ox1ff7]

  • 5>. 第五行leqp -0x18(%rbp),%rax,是取内存地址,将rbp寄存器中的地址减去0x18后得到的值,赋值给rax寄存器中

  • 6>. 第六行jmp是跳转指令,CPU会直接跳转到目标地址去执行

  • 7>. 大家应该发现了AT&T汇编总比Intel汇编多一位,例如:AT&T是movl,Intel就是mov, AT&T汇编的最后一位代表操作数,意思是要操作多少个字节的空间。

    • 例如movl $3,%rax,这句汇编的最后一位l,是long的缩写,代表操作数的长度是4个字节,要操作4字节的空间,将来要存放3的时候,CPU就分配4个字节的寄存器空间用来存放3

注意: movq和leaq的区别:

  • movq 是根据内存地址找出数据后,再将数据赋值给寄存器。

    • 例如:mov -0x18(%rbp),%rax,就是拿rbp寄存器存的地址减去 0x18 得到的地址,再从这个地址取出具体数据,存放到rax寄存器中
  • leaq 是将算出来的地址值,直接给寄存器。

    • 例如:leaq -0x18(%rbp),%rax,就是将rbp寄存器存的地址减去0x18得到的地址,直接存放到rax寄存器中

注意: jmp和call的区别:

  • jmp跳到某个地址后,中间的指令就不执行了。

    • 例如:刚开始执行在0x00000001处,执行jmp 0x00000008后,就直接跳转到目标指令了,中间的指令就跳过不执行了
  • call指令一般都是执行某个函数,经常与ret指令配合使用,会在函数执行完后返回到函数调用处

    • 例如:call *%rax 调用寄存器rax中存的地址(*代表间接调用,函数地址可能是动态的),调用结束后,会返回到调用函数的这一行指令

五、寄存器

    1. 寄存器是用来存放数据的,肯定需要存储空间才行,寄存器的大小和CPU有关,你是32位的CPU,那么你的寄存器也都是32位的
    1. 寄存器也是逐渐发展的,从开始的1个字节的寄存器,慢慢发展为2个字节的,4个字节的,8个字节的。

      • 为了兼容以前的寄存器,8个字节的寄存器会分出来4个字节当做4个字节的寄存器,如下图,为了兼容2个字节的寄存器,4个字节的寄存器又拿出最低的2个字节作为2个字节的寄存器,这样做,8位的寄存器,就能兼容之前的4个字节的寄存器、2个字节的寄存器、1个字节的寄存器了。


        寄存器
    1. 在AT&T汇编中:
    • r开头的寄存器都是占8个字节,也就是这个寄存器可以存储8个字节的数据,例如rax、rbx、rcx等寄存器;

    • 以e开头的寄存器占4个字节,也就是这个寄存器可以存储4个字节的数据;

    • ax、bx、cx寄存器占2个字节,也就是这个寄存器可以存储2个字节的数据;

    • ah、al、bh、bl寄存器占用1个字节,也就是这个寄存器可以存储1个字节的数据;

    1. 我们来看两句汇编代码巩固一下以上知识
    • 1>.movq $0xa,%rax,这句汇编的意思是将16进制0xa(也就是十进制的10)存放到rax寄存器中,操作数是q,代表操作 8 个字节的空间,所以寄存器rax中的数据就应该是0xa 0x0 0x0 0x0 0x0 0x0 0x0 0x0,如下图所示,由于rax、eax、ax、ah等寄存器共用一段存储空间,所以表面是你修改了rax寄存器,实际上eax、ax、ah等寄存器的值全都变成了0x0了
      movq $0xa,%rax
  • 2>.movl $0xa,%eax,这句汇编的意思是将16进制0xa存放到eax寄存器中,操作数是l,代表操作 4 个字节的空间,所以寄存器eax中的数据就应该是0xa 0x0 0x0 0x0,由于与rax寄存器共用存储空间,表面是是修改了eax寄存器,实际上rax寄存器也被修改了
    movl $0xa,%eax.png

六、AT&T汇编语言的常用技巧(这些技巧在以后分析汇编的时候会经常用到,建议熟记)

- 1. 0x712a(%rip) 一般都是全局变量,全局区 (这句汇编的意思是:rip寄存器的值 + 0x712a)
- 2. -0x10(%rbp) 一般都是局部变量,栈空间 (这句汇编的意思是:rbp寄存器的值 - 0x10)
- 3. 0x10(%rax)一般是堆空间 (这句汇编的意思是:rax寄存器的值 + 0x10)
- 4. rax、rdx寄存器一般存储函数返回值
- 6. rdi、rsi、rdx、rcx、r8、r9等寄存器常用来存放函数参数
- 7. rsp、rbp常用于存放栈操作
- 8. rip作为指令指针,存储着CPU下一条要执行的指令的地址,一旦CPU读取一条指令,rip会自动指向下一条指令

七、LLDB常用调试命令(加粗标红的命令以后会经常用,建议熟记)

    1. 读取某个寄存器的值:register read/格式,例如: register read/x rax
    1. 修改某个寄存器的值:register write 寄存器名称 数值,例如:register write rax 0
    1. 读取某个内存地址中的值x/数量-格式-字节大小 内存地址,例如: x/3xw 0x0100010 ,这句命令的中的第一个x代表读取内存,3代表3组,第二个x代表以16进制的格式,w代表4个字节,所以意思就是从0x0100010地址开始,以16进制的格式输出3组4个字节的内存数据,也就是以16进制的格式输出12个字节的数据。
    1. 修改内存中的值:memory write 内存地址 数值,例如:memory write 0x100010
    1. 上述命令中的的格式补充 :x代表16进制,f是浮点,d是十进制

      上述命令中字节大小补充:b - byte - 1字节,h - half word - 2字节,w - word - 4字节,g - giant word - 8字节

    1. 源码单步运行,子函数当做一个整体:next或者n
    1. 源码单步运行,遇到子函数会进入子函数:step或者s
    1. 汇编单步运行,子函数当做一个整体:nexti或者ni
    1. 汇编单步运行,遇到子函数会进入子函数:stepi或者si
    1. 直接执行完当前函数所有代码,返回函数调用处:finish
    1. 打印函数调用栈:bt

八、内存常用知识

    1. iOS领域,内存地址从低到高分为:代码区、常量区、全局区(数据段)、堆空间、栈空间、动态库
    1. 我们平常写的代码、函数都是不占用内存的,放在代码区
    1. 在程序运行过程中是不能往常量区放东西的,全局区是允许的
  • 4.基于引用计数的ARC内存管理是针对堆空间的,代码区、常量区、全局区、栈空间的内存不需要我们管理

    1. iOS平台中内存是以字节为单位的分配的;malloc分配的堆空间的的内容是以16个字节为单位的,也就是堆空间最少会分配16个字节的空间。
    1. MacO可执行文件的虚拟内存地址是0x10000000,在MacO文件里找地址需要用真实地址减去虚拟内存的地址,才是MacO文件里的地址
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342