# arm64_programming_practice **Repository Path**: longlongint/arm64_programming_practice ## Basic Information - **Project Name**: arm64_programming_practice - **Description**: 《ARM64体系结构编程与实践》一书 配套实验参考代码 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 32 - **Created**: 2026-06-28 - **Last Updated**: 2026-07-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 本地资料路径: F:\baiduDownload\奔跑吧Linux合集 4季+死机专题+vim+git\奔跑吧Linux合集 4季+死机专题+vim+git视频\第3季 ARM64体系结构与编程 F:\baiduDownload\奔跑吧Linux合集 4季+死机专题+vim+git\奔跑吧Linux合集资料\第3季Arm配套资料\芯片手册\芯片原版 ## 1. A64指令介绍 1. A64 指令集只能运行在aarch64环境中 2. 所有A64汇编指令都是32bits宽 表C1-2 通用寄存器、零寄存器以及栈指针命名 | 名称 | 位宽 | 编码值 | 说明 | | ---- | ---- | ------ | ---------------- | | Wn | 32位 | 0~30 | 0~30号通用寄存器 | | Xn | 64位 | 0~30 | 0~30号通用寄存器 | | WZR | 32位 | 31 | 零寄存器 | | XZR | 64位 | 31 | 零寄存器 | | WSP | 32位 | 31 | 当前栈指针 | | SP | 64位 | 31 | 当前栈指针 | ### 补充说明(AArch64架构特性) 编码`31`是复用编码:CPU会根据指令上下文自动区分,该编码代表零寄存器(XZR/WZR)或是栈指针(SP/WSP); - 以`W`开头 = 访问寄存器低32位;以`X`开头 = 访问完整64位寄存器; - 零寄存器只读,读取永远得到数值0,写入操作无效;栈指针专门用于管理程序栈内存. ## A64指令分类 - 内存加载和存储指令 - 多字节内存加载和存储 - 算术和移位指令 - 移位操作 - 位操作指令 - 条件操作 - 跳转指令 - 独占访存指令 - 内存屏障指令 - 异常处理指令 - 系统寄存器访问指令 --- # 1. ldr指令和str指令 ARMv8架构也是基于指令加载和存储的架构(Load/Store Architecture) 加载/存储指令格式: 1. LDR 目标寄存器, <存储器地址> //把存储器地址的数据加载到目标寄存器中 2. STR 源寄存器, <存储器地址> //把源寄存器的值存储到存储器中 ### 简要释义 - LDR(Load):读内存,将内存指定地址的数据读取放入寄存器 - STR(Store):写内存,将寄存器里的数据写入内存指定地址 这是ARM典型Load/Store架构的核心访存指令,运算指令只能操作寄存器,不能直接读写内存. ### 加载和存储指令变种 | 指令 | 说明 | | ----- | ----------------------------------------- | | LDR | 数据加载指令 | | LDRSW | 有符号的数据加载指令,大小为字(word) | | LDRB | 数据加载指令,大小为字节 | | LDRSB | 有符号的加载指令,大小为字节 | | LDRH | 数据加载指令,大小为半字(Halfword) | | LDRSH | 有符号的数据加载指令,大小为半字(Halfword) | | STRB | 数据存储指令,大小为字节 | | STRH | 数据存储指令,大小为半字 | # 2. 异或指令 ## 一、异或的3个小特点(右上角红色标注) 1. $0^\wedge0=0,\ 0^\wedge1=1$,0异或任何数 = 任何数 2. $1^\wedge0=1,\ 1^\wedge1=0$,1异或任何数 = 任何数取反 3. 任何数异或自己 = 把自己置0 ## 二、异或的几个小妙用 ### (1) 使某些特定的位翻转 例如想把`10100001`的第2位和第3位翻转,则可以将该数与`00000110`进行按位异或运算. $$ 10100001 \wedge 00000110 = 10100111 $$ ### (2) 交换两个数 例如交换两个整数 $a=10100001,\ b=00000110$ 的值,可通过下列语句实现: ```c a = a^b; //a=10100111 b = b^a; //b=10100001 a = a^b; //a=00000110 ``` ### (3) 在汇编里让变量设置为0 ```asm eor x0, x0 ``` ### (4) 判断两个数是否相等 ```c return ((a ^ b) == 0) ``` --- ### 补充知识点对应AArch64汇编 1. `eor x0, x0`:寄存器自身异或,快速清零X0,等价`mov x0, #0`; 2. `EOR Rd, Rn, #mask`:用掩码立即数翻转指定位,对应你之前看的`EOR (immediate)`指令手册. # 条件码 ## 表1.12 常见的条件操作后缀 | 条件后缀 | 含义 | 标志 | 条件码 | | -------- | -------------------- | --------------- | ------ | | EQ | 相等 | Z=1 | 0b0000 | | NE | 不相等 | Z=0 | 0b0001 | | CS/HS | 无符号数大于或者等于 | C=1 | 0b0010 | | CC/LO | 无符号数小于 | C=0 | 0b0011 | | MI | 负数 | N=1 | 0b0100 | | PL | 正数或零 | N=0 | 0b0101 | | VS | 溢出 | V=1 | 0b0110 | | VC | 未溢出 | V=0 | 0b0111 | | HI | 无符号数大于 | (C=1) && (Z=0) | 0b1000 | | LS | 无符号数小于或等于 | (C=0) ∥ (Z=1) | 0b1001 | | GE | 带符号数大于或等于 | N = V | 0b1010 | | LT | 带符号数小于 | N!=V | 0b1011 | | GT | 带符号数大于 | (Z=0) && (N=V) | 0b1100 | | LE | 带符号数小于或等于 | (Z=1) ∥ (n!=V) | 0b1101 | | AL | 无条件执行 | — | 0b1110 | | NV | 无条件执行 | — | 0b1111 | ### 补充说明 1. 标志位释义: - Z:零标志;C:进位/借位标志;N:符号负标志;V:有符号溢出标志 2. `∥` 代表逻辑或、`&&` 代表逻辑与; 3. CS/HS、CC/LO 是两组同义后缀,分别对应同一种判断逻辑. # 9.1 AArch64 Dependent Features - `-EB`:用于大端模式的CPU,`-EL`:用于小端模式的CPU - `-mabi`:指定ABI模式,ilp32用于ELF32,lp64用于ELF64,默认值为lp64 - `-mcpu=processor+extension`:指定CPU型号,例如cortex-a72 - `-march=`:用于指定支持的架构,例如armv8.2-a 也可用 `aarch64-linux-gnu-as --help` 获取 ## 标题:特殊字符 - `//`:用作注释 - `#`:行首位置时代表注释;除此以外,还可用来标识立即数 - `#:lo12`:用于取出地址的低12位 ```asm adrp x0, foo ldr x0, [x0, #:lo12:foo] ``` - ldr 伪操作 ## Arm64特有的伪操作 - `.bss`:切换到bss段 - `.dword`/`.xword`:定义64位数据 - `name .req register_name`:为寄存器创建别名 示例:`foo .req w0` # 连接器(Linker) 是一个程序,将一个或多个由编译器或汇编器生成的目标文件外加库链接为一个可执行文件. ## ld命令 - `aarch64-linux-gnu-ld`:arm64 架构专用的链接器命令 - 查看全部命令参数:`aarch64-linux-gnu-ld --help` - Benos 项目示例代码: ```makefile benos.bin: $(SRC_DIR)/linker.ld $(OBJ_FILES) $(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -Map benos.map -o $(BUILD_DIR)/benos.elf $(OBJ_FILES) $(ARMGNU)-objcopy $(BUILD_DIR)/benos.elf -O binary benos.bin ``` ## ld 常用参数 - `-T`:指定自定义链接脚本文件 - `-Map`:生成映射文件(记录内存布局、符号对应地址) - `-o`:指定输出的 ELF 可执行文件名称 ## 一个简单的链接文件 ```ld SECTIONS { . = 0x100000; .text : { *(.text) } . = 0x80000000; .data : { *(.data) } .bss : { *(.bss) } } ``` ### 代码简要说明 1. `. = 0x100000`:定位计数器赋值,将`.text`代码段放置在物理地址`0x100000`处 2. `*(.text)`:搜集所有目标文件里的`.text`代码段内容 3. `. = 0x80000000`:重置地址计数器,`.data`数据段从`0x80000000`地址开始存放 4. 依次收集所有文件的`.data`初始化数据段、`.bss`零初始化段