Pseudoinstruction Base Instruction(s) Meaning Comment la rd, symbol auipc rd, symbol[31:12]; addi rd, rd, symbol[11:0] Load address With .option nopic (Default) la rd, symbol auipc rd, symbol@GOT[31:12]; l{w|d} rd, symbol@GOT[11:0](rd) Load address With .option pic
la 加载的指令地址是相对的(大约所有用到符号地址的伪指令,地址都是相对的)。或者说,编译这类指令时,会假设一个当前的 pc,然后根据当前 pc 推算目标符号的位置。因此,如果程序加载到不是链接脚本指定的位置,或启用虚存,将 pc 搬移到另一个位置,符号表产生的位置都会随之改变,相对的才是不变的。
extern "C" {
fn symbol();
}
就是符号表在 rust 里的表示。symbol
的值和 la
加载出来的一样。
使用这个过程跳到高处的虚存:
# 从地址空间的低处跳到地址空间高处对应位置并挪动栈指针
# -------------------------------
_jump_higher: # fn jump_heigher(offset: usize) {{
add ra, ra, a0 # $t0 += offset;
add sp, sp, a0 # $sp += offset;
ret # }}
# -------------------------------
但是必须注意,寄存器里存放的所有地址也要跟着一起跳。本质上说,内核映射到高地址是为了给用户让出空间,所以跳后直接解除对跳板页的映射也得应该正确的,一切对跳板页上地址的映射都必须释放,或者跟着 pc 鸡犬升天。这里跟着跳了栈指针。