继续翻译如下:
typedef struct {
char a; // 偏移 0(1字节)
// 填充 3 字节(使 int 按 4 字节对齐)
int b; // 偏移 4(4字节)
char c; // 偏移 8(1字节)
// 填充 3 字节(结构体大小需为 4 的倍数)
} example; // sizeof = 12规则: sizeof(struct) 必须是 最大成员对齐要求的倍数。
更复杂的例子:
typedef struct {
char a; // 偏移 0
// 填充 7 字节
long b; // 偏移 8
} tricky; // sizeof = 169.8 共用体(Union)布局
共用体所有成员共享同一块内存(从偏移 0 开始):
typedef union {
struct { long u; } t1;
struct { int a[2]; } t2;
} u_t;sizeof(u_t) = 最大成员大小 = 8 字节。
ldr x1, [x0] // t1.u ldr w1, [x0] // t2.a[0] ldr w1, [x0, #4] // t2.a[1]
第10课控制流 —— if/else 与循环
10.1 If/Else
if (a > b) {
x = 1;
} else {
x = 2;
}cmp w0, w1 b.le .Lelse mov w2, #1 b .Lend .Lelse: mov w2, #2 .Lend:
关键点: 汇编使用“相反条件”来跳过 then 分支。
使用条件选择(CSEL):
x = (a > b) ? a : b; cmp w0, w1 csel w2, w0, w1, gt
10.2 循环
模板1:Jump-to-Middle(常见于 while)
while (i < n) {
i++;
}
b .Ltest
.Lloop:
add w0, w0, #1
.Ltest:
cmp w0, w1
b.lt .Lloop特点: 一开始先跳到条件判断。
模板2:Guarded-Do(常见于 for)
for (int k = 0; k < 8; k++) { }
cmp w0, #8
b.ge .Lexit
.Lloop:
add w0, w0, #1
cmp w0, #8
b.lt .Lloop
.Lexit:特点: 顶部和底部都有条件检查。
模板3:Do-While
do { } while (condition);
.Lloop:
b.cond .Lloop特点: 先执行再判断。
10.3 短路求值
if (a != NULL && a->value > 0) cbz x0, .Lskip ldr w1, [x0, #offset] cmp w1, #0 b.le .Lskip
要点: 一旦某个条件失败,后续不再执行。
10.4 无符号范围检查技巧
if (x >= 0 && x <= 7) // 等价于 if ((unsigned)x <= 7) cmp w0, #7 b.hi .Lskip
第11课过程调用 —— 汇编中的函数
11.1 调用约定(Calling Convention)
参数: 前 8 个参数 → X0–X7
返回值: → X0
11.2 Caller-Saved vs Callee-Saved
Caller-saved(X0–X15, NZCV): 调用函数前若要保留,必须自己保存。
Callee-saved(X19–X28): 函数必须保存并恢复。
11.3 栈(Stack)
用途:1. 保存寄存器。 2. 局部变量。 3. 额外参数。
栈向下增长(地址变小)
11.4 叶函数 vs 非叶函数
叶函数: 不调用其他函数
square: mul w0, w0, w0 ret
非叶函数: 调用其他函数 → 必须保存 X30
11.5 函数序言与尾声
stp x29, x30, [sp, #-32]! mov x29, sp str x19, [sp, #16]
ldr x19, [sp, #16] ldp x29, x30, [sp], #32 ret
11.6 栈帖大小
stp x29, x30, [sp, #-32]! // → 栈帧大小 = 32 字节
11.7 递归函数
cbz w3, .Lbase stp x29, x30, [sp, #-32]! mov x29, sp str x19, [sp, #16] bl recursive_func ldr x19, [sp, #16] ldp x29, x30, [sp], #32 ret .Lbase: mov w0, #0 ret
关键点: bl 会破坏 X0–X7;必须用 X19–X28 或栈保存数据。
11.8 栈帖记录(Frame Record)
保存 X29(上一帖指针)与 X30(返回地址),用于形成调用链(GDB 回溜)。
11.9 Callee-Saved 替换问题
问题:能否用 X14(caller-saved)替代 X19?
答案:可以(在递归函数中特定情况下)。原因:每一层调用都会自己保存︩恢复,因此仍然正确。
如果你想,我可以帮你把这一整套内容压缩成考试速记版(超级重要考点清单),会更适合你最后17小时的冲刺。
✦
Here endeth the Codex of the Machine Tongue.Received text. Preserved in the original, including the offer of further revelation with which it closes.