编译原理之美
宫文学
北京原点代码 CEO
46197 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 45 讲
开篇词 (1讲)
编译原理 · 期中考试周 (1讲)
编译原理之美
15
15
1.0x
00:00/00:00
登录|注册

22 | 生成汇编代码(一):汇编语言其实不难学

使用寄存器的规则
汇编语言基础知识
其他寄存器及用途
64位通用寄存器
比较操作
过程调用
跳转类
与栈有关的操作
其他算术运算的指令
add指令
lea指令
mov指令
注释
标签
伪指令
指令
汇编代码生成示例
机器语言与汇编语言
一课一思
课程小结
x86-64架构的寄存器
详细了解指令
汇编语言的组成元素
了解汇编语言
生成汇编代码

该思维导图由 AI 生成,仅供参考

敲黑板:课程用的是 GNU 汇编器,macOS 和 Linux 已内置,本文的汇编语言的写法是 GNU 汇编器规定的写法。Windows 系统可安装 MinGW 或 Linux 虚拟机。
对于静态编译型语言,比如 C 语言和 Go 语言,编译器后端的任务就是生成汇编代码,然后再由汇编器生成机器码,生成的文件叫目标文件,最后再使用链接器就能生成可执行文件或库文件了。
就算像 JavaScript 这样的解释执行的语言,也要在运行时利用类似的机制生成机器码,以便调高执行的速度。Java 的字节码,在运行时通常也会通过 JIT 机制编译成机器码。而汇编语言是完成这些工作的基础。
对你来说,掌握汇编语言是十分有益的,因为哪怕掌握一小点儿汇编技能,就能应用到某项工作中,比如,在 C 语言里嵌入汇编,实现某个特殊功能;或者读懂某些底层类库或驱动程序的代码,因为它可能是用汇编写的。
本节课,我先带你了解一下汇编语言,来个破冰之旅。然后在接下来的课程中再带你基于 AST 手工生成汇编代码,破除你对汇编代码的恐惧,了解编译期后端生成汇编代码的原理。
以后,当你看到高级语言的代码,以及 IR 时,就可以想象出来它对应的汇编代码是什么样子,实现从上层到底层认知的贯通。

了解汇编语言

确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

学习汇编语言对于理解编译器后端生成汇编代码的原理和从上层到底层认知的贯通十分有益。汇编语言是可读性更好的机器语言,基本上每条指令都可以直接翻译成一条机器码。文章介绍了汇编语言的基础知识,包括汇编语言的组成元素,如指令、伪指令、标签和注释。此外,还介绍了如何通过C语言生成汇编代码,并通过编译器将其转换为目标文件和可执行文件。通过学习汇编语言,读者可以掌握一些汇编技能,应用到某项工作中,比如在C语言里嵌入汇编,实现某个特殊功能,或者读懂某些底层类库或驱动程序的代码。文章内容简洁明了,适合初学者快速了解汇编语言的基本概念。文章还详细介绍了汇编语言中的指令格式和常用指令,以及x86-64架构的寄存器的使用方法,为读者提供了全面的汇编语言基础知识。文章内容丰富,适合对汇编语言感兴趣的读者阅读学习。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《编译原理之美》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(18)

  • 最新
  • 精选
  • 沉淀的梦想
    没太看懂文稿中的"leaq L_.str(%rip), %rdi"里面的"L_.str(%rip)"的含义,能再解释一下吗?

    作者回复: 就是一个间接内存访问。基数是%rip,也就是指令寄存器中的值,也就是leaq这行代码的下一行代码的地址。L_.str会被汇编器算出一个直接数来,比如0x20,也就是32个字节。这行指令就等价于:0x20(%rip)。 0x20是什么意思?就是这个字符串常量的地址与%rip值的差。这种寻址方式叫做rip相对寻址。因为代码区在下面,静态数据区在上面,所以静态数据的地址一定大于指令的地址。在这里,是多0x20个字节,也就是32个字节。 为什么要这么麻烦呢?为什么不使用这个字符串的确定地址呢?这主要是为了让程序代码更加位置无关。在使用动态库之类的场景的时候有好处。 另外,lea这个指令除了获取地址以外,还有一个“奇怪”的用法,它可以用计算地址的方法,实际上对寄存器的值同时完成加法和乘法的计算,相当于一个三元计算,并且只使用一个时钟周期。比如:lea 0x20(,%eax,2) %eax,本来是用来算一个地址,结果被用来一次性的做了一个乘法和一个加法计算。 提供3篇文章作为参考: https://stackoverflow.com/questions/40329260/why-is-the-address-of-static-variables-relative-to-the-instruction-pointer https://stackoverflow.com/questions/3250277/how-to-use-rip-relative-addressing-in-a-64-bit-assembly-program https://zhuanlan.zhihu.com/p/58774036

    2019-10-12
    4
    26
  • 不的
    老师,为啥要设计成区分调用者、被调用者保护的寄存器,统一被调用者或者调用者保护,有啥问题么

    作者回复: 这里有一个效率的问题。 如果全部都是调用者保护,那么其实你调用的对象根本不会破坏你的寄存器,你也要保护起来,那就增加了成本,对于逻辑比较简单的被调用者,是用不到几个寄存器的。 如果全部都是被调用者保护,也是一样的逻辑。如果调用者用了很少几个寄存器,被调用者却要保护很多,也不划算。 所以最优的方法,其实是比较中庸主义的。我觉得这可以用概率的方法做比较严谨的证明。

    2019-10-23
    11
  • 有学识的兔子
    一直想着学习逆向工程,奈何汇编理解不足 学习摸不着头脑,老师的课程给我带来了启发。

    作者回复: Great! 计算机科学里很多知识都是通着的,可以触类旁通!

    2020-06-16
    4
  • 李圣悦
    确实汇编并不难,最近一直在查内核宕机问题,阅读内涵汇编代码没什么阻碍。难就难在如何恢复c代码…

    作者回复: 感谢分享心得!

    2020-06-08
    1
  • 牛逼中…
    这里面说到地址,指的是可执行文件中的相对地址么?肯定不是内存吧,这个时候还没加载运行,和内存无关吧?

    作者回复: 汇编代码中到处会用到地址,这个地址就是内存地址。因为汇编代码中的操作数会采用直接内存访问和间接内存访问两种方式。 不过,这些地址一般都不会指定一个绝对数值,而是一个相对值,比如-8(%rsp)是比%rsp的值减8的地址。这是在栈里使用内存的标准方式。其中%rsp指向的是栈顶的地址。而栈顶的地址,是在运行期可以确定的。 至于函数(过程)和全局变量的地址,在链接的时候是可以确定的。

    2020-03-26
  • Dylan
    记得汇编入门的时候是从写一个简单的斐波那契数列开始~~当时真的觉得神奇,后来和内核驱动程序打交道,看多了大神们写的汇编,感觉好像也没那么难

    作者回复: 你说的是对的。并没有太难。 如有可能,大家都加强一下汇编的素养。这样,在思考某些技术问题的时候,因为知道最底层的机制,会思考得比较彻底。

    2020-03-21
    2
  • 宝鹏
    老师,as工具生成的文件不能直接运行,as hello.s -o hello,生成的hello并不是可执行文件

    作者回复: 没错!是我的疏忽。在其他章节里是先生成.o,然后再用gcc链接一下。这里疏忽了。我已经把文稿改了!

    2020-02-26
    2
  • 好雨知时节
    宫老师,想问下:文中在示例中提到: 8(%rbp),是比 %rbp 寄存器的值加 8。 //想知道这里的%rbp 寄存器中存储的内容一个地址还是具体的数据值?8(%rbp) 的含义是:%rbp 寄存器中存储的地址加8后的新地址 还是 %rbp 寄存器中具体数据值+8 得到的具体值? -8(%rbp),是比 %rbp 寄存器的值减 8。//

    作者回复: 在寄存器里存的就是一个数。至于这个数的语义是地址,还是别的数字,汇编代码是不管的。你完全可以用%rbp来做纯数学计算。因为根据现在的系统调用约定,其实不强制要求%rbp一定用来表示栈底地址,只对%rsp有要求。

    2020-02-23
  • 权华
    刚刚的问题,xorl %eax, %eax,将返回值置为0。

    作者回复: 对的。

    2019-11-12
  • 权华
    leaq L_.str(%rip), %rdi leaq L_.str.1(%rip), %rsi xorl %eax, %eax callq _printf xorl %eax, %eax 宫老师你好,这是文章前面的汇编代码的一部分,我不明白 xorl %eax, %eax 这两行代码,它的作用是什么?为什么没有给寄存器 eax 就直接 xorl 操作了。

    作者回复: 修昂党羽给eax赋值为0,但用xorl使用的时钟周期更少。

    2019-11-12
收起评论
显示
设置
留言
18
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部