13.4. 汇编伪指令类
【例1】 li 指令示例
# 加载小立即数(单条指令完成)
li.w $t0, 42 # 将42加载到$t0
# 加载16位范围内的立即数
li.w $a0, 0x1234 # 加载0x1234到$a0
# 加载大立即数(自动拆分为多条指令)
li.d $s0, 0x1FFFFFFFF # 加载64位大立即数(汇编器自动展开为 lu12i.w + ori + lu32i.d + lu52i.d)
# 加载系统调用相关立即数
li.w $a7, 93 # exit系统调用号:93
li.w $a0, 100 # 退出码100
【例2】 move 指令示例
move $r4, $r5 # $r4 = $r5
move $r6, $r0 # $r6 = 0 (清零)
【例3】 la 指令示例:PC 相对寻址
当目标符号位于 PC 相对寻址范围内(±1GB)时,la 通常会展开为:
la $rd, symbol
pcaddu12i $rd, %pcrel_hi(symbol) # 加载高20位
addi.d $rd, $rd, %pcrel_lo(symbol) # 添加低12位偏移
【例4】 la 指令示例:绝对地址
需要加载绝对地址时,例如访问全局变量地址,la 可能展开为:
# 假设我们有: la $rd, global_var
lu12i.w $rd, %hi(global_var) # 加载高20位
addi.d $rd, $rd, %lo(global_var) # 添加低12位
【例5】 la 指令示例:构造64位地址
对于完整64位地址,la 可能需要展开为多条指令:
# 复杂情况下的展开
lu12i.w $rd, %hi(symbol) # 高20位
ori $rd, $rd, %lo(symbol) # 低12位
slli.d $rd, $rd, 32 # 左移32位
lu32i.d $t0, %hi2(symbol) # 高32-51位
ori $t0, $t0, %lo2(symbol) # 低32-43位
or $rd, $rd, $t0 # 合并两部分
【例6】 la 指令示例:通过 GOT(Global Offset Table)加载
在位置无关代码(PIC)中,访问全局符号通常需要经过 GOT:
# 加载GOT中符号的地址
la $t0, %got(symbol) # 加载symbol在GOT中的偏移
ld.d $t1, $t0, 0($gp) # 从GOT中加载实际地址
# 简化形式
la $t0, %call16(symbol) # 用于函数调用的GOT偏移
【例7】 la 指令示例:加载 TLS(Thread-Local Storage)地址
访问线程局部存储变量时,可使用如下写法:
# 加载TLS变量地址
la $t0, %tls_ie(symbol) # Initial Exec模型
la $t0, %tls_le(symbol) # Local Exec模型
【例8】 la 指令示例:大小端模式
LoongArch64 支持动态切换大小端模式,符号地址加载时也要考虑当前字节序:
.byte_order little # 设置小端模式
la $t0, my_data # 按小端模式加载地址
.byte_order big # 设置大端模式
la $t0, my_data # 按大端模式加载地址
【例9】 call 指令示例
# 1. 调用本地函数
call my_function
# 2. 调用外部函数(通过PLT)
call printf
# 3. 调用通过寄存器间接寻址的函数
la $t0, function_pointer
call $t0
# 4. 带偏移的调用
call table_start, 16 # 调用table_start + 16处的函数
【例10】 ret 指令示例
my_function:
# 函数体
# ... 计算、处理等
# 返回
ret
# 带返回值的函数
add_numbers:
add.d $a0, $a0, $a1 # $a0 = $a0 + $a1
ret # 返回结果在$a0中
# 复杂函数
complex_function:
# 保存被调用者保存的寄存器
addi.d $sp, $sp, -16
st.d $s0, $sp, 0
st.d $s1, $sp, 8
# 函数逻辑
li $s0, 42
li $s1, 84
add.d $a0, $s0, $s1
# 恢复寄存器
ld.d $s0, $sp, 0
ld.d $s1, $sp, 8
addi.d $sp, $sp, 16
# 返回
ret
【例11】 jr 指令示例
# 1. 标准返回(等同于ret)
jr $ra
# 2. 从其他寄存器跳转
la $t0, alternative_return
jr $t0
# 3. 间接函数调用
function_pointer:
.dword my_function
.dword your_function
# 调用函数指针
ld.d $t0, $zero, function_pointer # 加载函数地址
jalr.hb $ra, $t0, 0 # 调用函数