MacOS Arm64 汇编 part 3 - MacOS Arm64 Assembly part 3
- manipulate memory
- function & stack
Defining Memory Contents
Basics
我们在 .data
段中编写内存内容,主要有以下表格描述的内容类型描述符,同时可以使用
Negative(-) 取相反数,以及 Complement(~)
取反两个整型数前缀
1 | label: 74, 0112, 0b00101010, 0x4A, 0X4a, |
其中 label
是这一段内存的标识符,后面的存储内容是连续的,通过逗号分隔同类型的数据。通过内容类型描述符指示不同类型的数据
| Directive | Description |
|---|---|
| .ascii | 用双引号括起来的字符串(不自动添加结束符) |
| .asciz | 以 0 字节结尾的 ASCII 字符串(自动在末尾添加 \0
终止符) |
| .byte | 1 字节整数(8 位有符号/无符号整数) |
| .double | 双精度浮点值(64 位 IEEE 754 浮点数) |
| .float | 单精度浮点值(32 位 IEEE 754 浮点数) |
| .octa | 16 字节整数(128 位整数) |
| .quad | 8 字节整数(64 位有符号/无符号整数) |
| .short | 2 字节整数(16 位有符号/无符号整数) |
| .word | 4 字节整数(32 位有符号/无符号整数) |
Fill
当需要一块连续且具有一定规律的内存片段时,可以采用
fill
1 | lable: .fill repeat, size, value |
这将重复填充大小为 size(Byte) 值为 value
的块 repeat 次
Repeat
通过这一语法可以重复其之间的语句指定次数,即一个复杂的重复模式
1 | label: count |
这将填充 count 次
Aligning Data
为了内存访问效率,因为 CPU 是按块读取内存的,而为了简化设计,块号都是呈 2 的倍数的,因此当我们在创建连续的内存片段时,需要进行对齐,这与 C/C++ 当中的结构体对齐逻辑一致
1 | .align 4 |
上面的代码即做了按 4 字节对齐
Loading a Register with an Address
我们可以通过 ldr 指令加载一个 64 bits
值到指定寄存器(PC 相对寻址)
包括下面的说法,这一节中的
ldr的实际指令是基于PC相对寻址模式,与手写的理解有所不同,在下一节我们会介绍其的非相对寻址模式
1 | ldr xd, =imm64 |
这是一条伪指令,实质为
1 | ldr xd, #offset |
offset 是相对于该 ldr
指令到这一立即数存储位置的偏移量
通过这一方法可以加载 PC 附近约 1MB
范围的内存,但加载的值可以超出指令长度,这既是这一指令的意义,对于更远的数据,以及带标签数据,在
OSX 中我们实际上使用如下方法在 xd 中加载其地址
1 | adrp xd, label@PAGE |
这里是采用分页的相对寻址(仍基于 PC),第一条
adrp 首先加载页基址,随后 add
加载偏移量,之所以分两条还是因为指令长度有限
Loading Data from Memory
在取得地址后,我们读取一个指定地址的数据我们仍采用 ldr
指令
1 | ldr{type} xd, [xs{, #offset}] |
type 见下表
| Type | Meaning |
|---|---|
| B | 无符号字节(Unsigned byte) |
| SB | 有符号字节(Signed byte) |
| H | 无符号半字(16 位,Unsigned halfword (16 bits)) |
| SH | 有符号半字(16 位,Signed halfword (16 bits)) |
| SW | 有符号字(Signed word) |
均为自低位起,
#offset可选
[]表示了这条指令的间接寻址模式,可以理解为*xs
#offset是自xs所存地址起的偏移量,可以理解为*(xs + offset)