文章目录1. 编译流程2. 可执行文件2.1 可重定位目标文件与可执行目标文件3. 汇编语法3.1 注释3.2 标签和符号3.3 指令伪指令3.3.1 对齐伪指令3.3.2 数据定义伪指令3.3.3 函数相关伪指令3.3.4 与段相关的伪指令3.3.5 宏3.3.6 文件相关的伪指令4. RISCV 汇编编译选项1. 编译流程通常情况下编译器编译一个可执行文件包含以下几个步骤预处理编译汇编链接输入层gcc -Egcc -Sgcc -cgcc -o阶段4: 链接 (Linker)合并多个 .o 文件解析符号引用跨文件函数调用链接标准库libc / libm / libstdc链接启动代码crt0 / crt1地址重定位分配最终内存地址输出: 可执行文件ELF / PE / Mach-O阶段3: 汇编 (Assembler)汇编指令 → 机器码二进制操作码生成符号表函数/变量地址映射生成重定位信息未解析的外部引用输出: 目标文件*.o / *.obj阶段2: 编译 (Compiler Proper)词法分析Token化语法分析生成 AST/GENERIC语义分析类型检查中间表示转换GENERIC → GIMPLE → RTL优化 PassSSA、内联、循环优化等代码生成输出汇编指令输出: 汇编代码*.s 文件阶段1: 预处理 (Preprocessor)处理 #include头文件展开处理 #define宏替换条件编译 #ifdef选择性保留代码删除注释添加行号标记输出: 纯净C代码*.i 文件源代码文件*.c / *.cpp / *.h2. 可执行文件可执行与可链接格式Executable and Linkable Format, ELF,一种文件格式常见的段代码段.text存放程序的可执行机器指令编译后的二进制代码。只读数据段.rodata存放只读常量数据。数据段.data存放已初始化的全局变量和静态变量。BSS段.bss存放未初始化或初始化为 0 的全局/静态变量。符号段.symtab记录程序中的符号信息函数名、变量名及其地址。可重定位代码段.rel.text记录代码中需要重定位的位置。可重定位数据段.rel.data记录数据段中需要重定位的位置。调试符号段.debug存放调试信息供 GDB 等调试器使用。2.1 可重定位目标文件与可执行目标文件可重定位目标文件在链接阶段和其他可重定位目标文件合并成一个可执行文件包含代码和数据所有段的起始地址不确定用0填充可重定位代码段.rel.text可重定位数据段.rel.data可执行目标文件可以执行的目标文件包含代码和数据所有段的起始地址都已经确定3. 汇编语法3.1 注释在.S文件中支持三种注释“//” 单行注释“#” 在一行开始表示注释整行“/**/” 多行注释注: .S文件会经过预处理器处理可以使用C语言中的注释方式经过预处理以后会被丢弃.s文件中只能用汇编注释#。3.2 标签和符号标签 (Label)后面紧跟冒号 :代表所在位置的地址。常用于跳转或函数入口。start: 或 loop_start: 都是标签。符号 (Symbol)指代一段数据或代码的名字但不一定需要紧跟冒号。通过 .equ、.set、#define仅 .S定义的常量或用 .globl 导出的函数名都是符号。label_name: # 普通标签冒号结尾 instruction 1: # 局部标签纯数字用于临时跳转 instruction jmp 1f # 1f 向前forward找下一个 1: jmp 1b # 1b 向后backward找上一个 1:类型示例说明全局符号main:、_start:默认局部可见需.global导出局部符号main:、_start:默认局部可见通常用.local声明局部标签1:、2:临时标记配合f/b使用符号赋值symbol 0x1000等价于常量不占内存等值伪指令.set name, 0x100定义符号常量符号代表所在的地址也可以当作变量或者函数来使用符号由字母数字‘_’ 和’.和$组成。局部标签不一定是符号数字标签就不是局部符号一定是符号表中的条目。3.3 指令伪指令指令是真正的机器指令汇编后直接生成对应的机器码并且寄存器必须小写指令可以是全大写或者全小写。[前缀] 操作码 [源操作数], [目的操作数]伪指令以点 . 开头是汇编器的命令不生成机器码控制汇编过程。伪指令可以实现如下功能符号定义数据定义和对齐汇编控制汇编宏段描述3.3.1 对齐伪指令.align 对齐填充数据来实现对齐可以填入0或者nop指令告诉汇编器.align 后面的汇编必须从下一个能被2^n整除的地址开始分配RISCV中第一个参数表示2^n大小.align expression [, fill_value [, max_bytes]]参数说明默认值expression对齐边界含义因架构而异必需fill_value填充字节值0x86/ 0x00 或 nop其他max_bytes最大填充字节数超过则跳过对齐无限制3.3.2 数据定义伪指令基本数据定义伪指令伪指令数据大小说明示例.byte8-bit (1 字节)定义字节.byte 0xFF, -1, A.short/.hword16-bit (2 字节)定义半字.short 0x1234, -300.long/.int/.word32-bit (4 字节)定义字.long 0x12345678.quad64-bit (8 字节)定义四字.quad 0x123456789ABCDEF0.octa128-bit (16 字节)定义八字.octa 0x....single/.float32-bit单精度浮点.float 3.14, -0.5.double64-bit双精度浮点.double 3.1415926535字符串定义伪指令伪指令自动补\0说明示例.ascii❌ 否ASCII 字符串原始.ascii Hello.asciz✅ 是ASCII 自动补零.asciz Hello.string✅ 是同.asciz.string Hello.string8✅ 是8-bit 字符.string8 Hello.string16✅ 是16-bit 宽字符.string16 Hello.string32✅ 是32-bit 宽字符.string32 Hello3.3.3 函数相关伪指令.global定义一个全局符号.include引用头文件.if,.else,.endif控制语句3.3.4 与段相关的伪指令.section.section name,flags.section: 表示接下来的数据或者指令会链接到哪个段中每一个段以段名为开始以下一个段名或者文件末尾为结束。字符全称含义ELF 段头标志aAllocatable段在运行时分配内存SHF_ALLOCeExclude链接时排除该段SHF_EXCLUDEwWritable段内容可写SHF_WRITExExecutable段内容可执行SHF_EXECINSTRMMergeable相同内容段可合并SHF_MERGESStrings段包含null 结尾字符串SHF_STRINGSGGroup段属于COMDAT 组SHF_GROUPTTLS线程局部存储段SHF_TLS?保留未知/保留标志—.pushsection和.popsection.pushsection name, flags, type # ... 在新段中定义内容 ... .popsection伪指令作用.pushsection保存当前段上下文切换到指定新段.popsection恢复之前保存的段上下文.section和.previous初始状态: 当前在 .text 段 .section .data, aw, progbits ──► 切换到 .data 记住: 上一个段是 .text [在 .data 中定义数据] .previous ──► 回到 .text上一个段 [继续在 .text 写代码] .section .rodata, a, progbits ──► 切换到 .rodata 记住: 上一个段是 .text.previous 后的当前段 [定义只读数据] .previous ──► 回到 .text特性.section.previous.pushsection.popsection记忆层数仅一层上一个段多层栈支持嵌套切换方式直接切换覆盖记忆压栈保存精确恢复嵌套支持❌ 不支持嵌套会丢失更早的段✅ 支持任意深度嵌套适用场景简单两段切换复杂多段嵌套、编译器生成安全性容易误用忘记当前段栈结构成对使用更安全3.3.5 宏汇编中的宏通过.macro和.endm定义.macro后面是宏的名称然后是跟宏的参数在宏里面使用参数要加“\”.macro add_1 p1 p2 add x0, \p1, \p2 .endm宏定义的时候可以设置一个初始值.macro reserve_str p00,p2 .endm # 由于第一个参数有一个默认值可以省略默认值 reserve_str ,b reserve_str a,b宏参数后面加.req表示在宏调用过程中必须传递一个值否则会编译出错3.3.6 文件相关的伪指令.incbin 伪指令可以把文件的二进制数据嵌入到当前位置。.include 伪指令可以把汇编代码插入到当前指令所在位置。4. RISCV 汇编编译选项选项作用常用值-fpic/-fPIC位置无关代码共享库-fPIC大模型-fno-pic绝对地址代码裸机/静态默认裸机-mabi整数/浮点/指针宽度lp64d,ilp32-march指令集扩展rv64gc,rv32imac-misa-specISA 规范版本20191213-mlittle-endian小端存储默认--mbig-endian大端存储-