MIPS架构下GOT/PLT工作机制及gp寄存器段错误调试咨询
Hey there, let's walk through exactly how that GP register setup sequence works in the classic MIPS GOT/PLT mechanism—since you're hitting a segfault tied to GP access, this should clarify what's going on under the hood.
First, a quick recap: On MIPS, the $gp (global pointer) register is used to quickly access global and static variables. It's designed to point to the middle of the global data section, so most variables can be reached with a small signed offset from $gp (since MIPS immediate offsets are limited to 16 bits). For dynamically linked binaries, this address can't be hardcoded (thanks to ASLR and dynamic loading), hence the need for the runtime initialization you're seeing.
逐行解析函数开头的汇编
Let's break down each line of that prologue:
lui gp,0xa: Thelui(Load Upper Immediate) instruction loads the 16-bit value0xainto the upper half of the$gpregister, zeroing out the lower 16 bits. So after this line,$gp = 0x000A0000(in 32-bit MIPS). This value comes from the linker at compile time, representing the upper 16 bits of the static virtual address for the middle of the global data section.addiu gp,gp,31444:addiu(Add Immediate Unsigned) adds the 16-bit immediate value31444(hex0x7AE4) to$gp. Now$gpholds the full static virtual address of the global data section's midpoint:0x000A0000 + 0x7AE4 = 0x000A7AE4. This is the address$gpwould use in a statically linked binary.addu gp,gp,t9:addu(Add Unsigned) adds the value of$t9(register $25) to$gp. This is the critical dynamic adjustment step for linked binaries.
完整初始化流程推导
Here's the full chain of how this results in a valid runtime $gp:
- Compile-Time Setup: The linker calculates the static virtual address of the global data section's midpoint, splits it into upper 16 bits (
0xa) and lower 16 bits (31444), and injects these values into the function prologue. It also records the static virtual address of the PLT (Procedure Linkage Table) entry for the function (e.g.,main). - Dynamic Loading: When the program starts, the dynamic linker loads the binary's
.text(code) and.data/.got(global data) sections into a random memory address (ASLR). This creates a load offset:actual_load_base - static_virtual_base. - Function Call via PLT: When
mainis called (either from the runtime loader or another function), the jump usesjalr $t9, which sets$t9to the actual runtime address ofmain's PLT entry. This address equals:static_plt_address + load_offset(since the entire.textsection is shifted by the load offset). - GP Correction: Inside
main's prologue:- The first two lines set
$gpto the static midpoint address (0x000A7AE4). - The
adduline adds$t9(static_plt_address + load_offset) to this static$gpvalue. But here's the key: the static$gpaddress and static PLT address are separated by a fixed, linker-known offset (since.textand.datasections are positioned at a fixed relative distance at compile time). So when you add them together, the static_plt_address cancels out, leaving you with:static_gp_address + load_offset—which is the actual runtime address of the global data section's midpoint.
- The first two lines set
- Valid GP Ready: Now
$gppoints to the correct location in memory, and the function can safely access global variables using small offsets from$gp.
为什么这和经典GOT/PLT机制相关
The $t9 register is central to MIPS' GOT/PLT setup because it's used to carry the dynamic load context into the function. In classic dynamic linking:
- The PLT acts as a trampoline for external function calls, redirecting to entries in the GOT (Global Offset Table).
- The GOT holds the actual runtime addresses of external symbols, which are resolved by the dynamic linker on first call.
- For functions within the same binary (like
main),$t9still carries the PLT entry address, which includes the necessary load offset to correct$gp—even if the function isn't an external symbol.
段错误的可能关联
If you're hitting a segfault related to $gp access, it's likely that this initialization isn't working correctly:
$t9might hold an invalid value (e.g., if the function was called without going through the PLT, so$t9wasn't set to the correct PLT entry address).- The dynamic linker failed to properly set up the PLT/GOT, leading to an incorrect load offset in
$t9. - A bug in the linker or compiler generated incorrect upper/lower 16-bit values for the static
$gpaddress.
内容的提问来源于stack exchange,提问作者EnTaroAdun

