- 在一个进程启动时,操作系统会为每个进程分配64位逻辑地址空间,并在MMU(Memory Management Unit, 内存管理单元)中维护一个逻辑地址向物理地址的映射。
-
操作系统将地址分为4KiB, 也就是4096B大小的页(Page), 将逻辑地址的页与物理地址的页进行映射。在一个页内相邻的逻辑地址对应的物理地址是相邻的,但是页之间的物理地址的关系是不确定的。
- Clang 是 LLVM项目的一个子项目,基于LLVM架构的C/C++/Objective-C编译器前端。
- LLVM 分前端和后端。中间是LLVM IR
- 如果需要支持一种新的编程语言,那么只需要实现一个新的前端
- 如果需要支持一种新的硬件设备,那么只需要实现一个新的后端
汇编器指令(Directive)
- 开头的都是汇编器指令,如例程中的.section,
- .section __TEXT, __text 可以用 .text 代替。
- .globl 名字和记号 .global _main
- 一个数字前加上$表示这个数本身。如果不加的话,则表示0这个地址里存储的数
- 在GAS语法中,寄存器名字前面一定要跟着%.
.equ定义字面量
.equ maxCount, 0x114514
之后就可用 $maxCount 代替 0x114514 如: movq $maxCount, %rax
对于push而言,如果我们一下子准备把许多值压入栈内,那么可以先用sub指令减小rsp, 再用mov移动。比如说:
# method 1
pushq $0x114514
pushq $0x1919
pushq $0x810
# method 2
subq $24, %rsp
movq $0x114514, 16(%rsp)
movq $0x1919, 8(%rsp)
movq $0x810, (%rsp)
-
rbp base pointer, 基地址指针,一般是用来使用偏移量寻址的
-
lea是load effective address的简称,其拥有两个操作数。我们可以像这样使用:表示将-8(%rbp)的地址赋给rax。在64位处理器下,地址都是64位的。因此,lea后面一定是q, 而不能是别的东西
leaq -8(%rbp), %rax
全局变量
- __DATA__段中,__data节存放所有非const的已经被初始化过的变量
- __bss节存放所有未被初始化的static的变量
- __common节存放所有未被初始化过的外部全局变量
- 类似于.text,我们可以用.data来代替.section __DATA, __data
-
用.bss代替.section __DATA, __bss
- 我们引入汇编器指令.byte, .short, .long, .quad. 它们分别代表1字节,2字节,4字节和8字节。比如说,我如果想告诉汇编器我们要存放的数据0x114514占8个字节,那么就可以写
.data
.quad 0x114514
- 汇编器也对此专门做了优化。当我们使用寻址方式标签(%rip)时,汇编器不会将其看作rip + 标签,而是会在汇编时就计算出标签距离此指令的下一条指令的地址的距离,然后用距离替换标签。比如说:
# dataTest.s
.data
a: .quad 0x114514
.text
.globl _main
_main:
movq a(%rip), %rax
retq
call : jump到参数指定地址,并将下一条指令地址压栈。 ret : jump到栈顶地址,并弹出栈顶。
- 参数传递按从左至右的顺序依次是:rdi, rsi, rdx, rcx, r8, r9. 如果参数多于6个,则将多于6个的部分按从右往左的顺序压入栈内。
- rbp, rbx, r12, r13, r14, r15 属于主调函数,其他寄存器属于被调函数。被调函数如果想使用以上寄存器,需要保留初始值。