You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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: The lui (Load Upper Immediate) instruction loads the 16-bit value 0xa into the upper half of the $gp register, 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 value 31444 (hex 0x7AE4) to $gp. Now $gp holds the full static virtual address of the global data section's midpoint: 0x000A0000 + 0x7AE4 = 0x000A7AE4. This is the address $gp would 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:

  1. 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).
  2. 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.
  3. Function Call via PLT: When main is called (either from the runtime loader or another function), the jump uses jalr $t9, which sets $t9 to the actual runtime address of main's PLT entry. This address equals: static_plt_address + load_offset (since the entire .text section is shifted by the load offset).
  4. GP Correction: Inside main's prologue:
    • The first two lines set $gp to the static midpoint address (0x000A7AE4).
    • The addu line adds $t9 (static_plt_address + load_offset) to this static $gp value. But here's the key: the static $gp address and static PLT address are separated by a fixed, linker-known offset (since .text and .data sections 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.
  5. Valid GP Ready: Now $gp points 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), $t9 still 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:

  • $t9 might hold an invalid value (e.g., if the function was called without going through the PLT, so $t9 wasn'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 $gp address.

内容的提问来源于stack exchange,提问作者EnTaroAdun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:01:31