Open gballet opened 1 week ago
I'm a bit confused at why you're even defining a GP symbol yourself. The linker will take care of that for you anyway. Also, the symbol is supposed to be named __global_pointer$
according to the RISC-V ABI. (You're also missing a .option pop
directive in _start
.)
Anyway, I don't see anything obviously wrong here?
❯ readelf --relocs test
Relocation section '.rela.dyn' at offset 0x113c contains 3 entries:
Offset Info Type Sym.Value Sym. Name + Addend
10000350 00000003 R_RISCV_RELATIVE 100002f5
10000384 00000003 R_RISCV_RELATIVE 10000350
10000424 00000003 R_RISCV_RELATIVE 1000034e
The 3rd relocation applies to the GOT slot that points to __global_pointer
. As expected, it fixes up the slot to point to the end of the .text
section, which is where you defined __global_pointer
to be.
I suspect you're looking at the wrong thing. Your la
pseudo-instructions are likely the problem:
❯ objdump --disassemble=_start test
test: file format elf32-littleriscv
Disassembly of section .text:
10000328 <_start>:
10000328: 00000197 auipc gp,0x0
1000032c: 0fc1a183 lw gp,252(gp) # 10000424 <_DYNAMIC+0x74>
10000330 <.Lpcrel_hi1>:
10000330: 00000117 auipc sp,0x0
10000334: 0f812103 lw sp,248(sp) # 10000428 <_DYNAMIC+0x78>
10000338: 00000317 auipc t1,0x0
1000033c: 00a30067 jr 10(t1) # 10000342 <main>
...
This is obviously not going to work; gp
is garbage at this point, so accessing the GOT through it is nonsensical. Bit of a chicken and egg situation.
Fixing it up to be lla
:
❯ objdump --disassemble=_start test
test: file format elf32-littleriscv
Disassembly of section .text:
10000320 <_start>:
10000320: 00000197 auipc gp,0x0
10000324: 02618193 add gp,gp,38 # 10000346 <__global_pointer>
10000328 <.Lpcrel_hi1>:
10000328: 00000117 auipc sp,0x0
1000032c: cd810113 add sp,sp,-808 # 10000000 <__stack_start>
10000330: 00000317 auipc t1,0x0
10000334: 00a30067 jr 10(t1) # 1000033a <main>
...
That looks a lot more sensible!
That's a lot of good points: indeed the symbol name is wrong, and I shouldn't be setting gp
. That unblocks me, so thank you very much for that.
This being said, I think there is something wrong (at least, that I can't explain): if I keep the la
(and therefore use the .got
section), but use a0
instead of gp
, the corresponding value is still 0. Sure, as you correctly pointed out, this won't work anyway because of the circular register use, Still, it seems to me that the correct value should be found in the .got
- and not 0.
Interestingly, in spite of this error, the relocation dump resolves it correctly (it's not using .got
, I assume):
Relocation section '.rela.dyn' at offset 0x20bc contains 34 entries:
Offset Info Type Sym.Value Sym. Name + Addend
...
10000314 00000003 R_RISCV_RELATIVE 10001000
I'm just leaving this issue open in case someone wants to investigate/add some input. As far as I'm concerned, the matter is settled, though, so feel free to close this issue if this is not deemed interesting.
This being said, I think there is something wrong (at least, that I can't explain): if I keep the
la
(and therefore use the.got
section), but usea0
instead ofgp
, the corresponding value is still 0.
You mean la a0, __global_pointer
? That does actually "work":
10000328 <_start>:
10000328: 00000517 auipc a0,0x0
1000032c: 0fc52503 lw a0,252(a0) # 10000424 <_DYNAMIC+0x74>
I put "work" in quotes here because of course it only works if the relocation on the GOT slot has actually been applied. Which means that:
This is obviously not going to work;
gp
is garbage at this point, so accessing the GOT through it is nonsensical. Bit of a chicken and egg situation.
I was actually wrong here. It is a chicken and egg situation, but not for the reason I wrote. la gp, __global_pointer
would work fine too if the relocation was applied.
Anyway, in a freestanding PIE executable, it's your responsibility to make sure that relocations are applied one way or another. Here's how we do it in Zig for statically-linked executables w/o libc:
https://github.com/ziglang/zig/blob/8594f179f9d70fbc3bf39111c4e1f147d4a6dc3c/lib/std/start.zig#L483-L488 https://github.com/ziglang/zig/blob/8594f179f9d70fbc3bf39111c4e1f147d4a6dc3c/lib/std/os/linux/pie.zig#L202-L304
So you might do it that way or have your executable loader do it, or something else entirely.
That's a lot of good points: indeed the symbol name is wrong, and I shouldn't be setting
gp
. That unblocks me, so thank you very much for that.
You probably do want to be setting gp
unless some other code is doing it for you. The linker only takes care of creating the __global_pointer$
symbol for you; it doesn't actually initialize the gp
register. Here's what we do in Zig:
Zig Version
0.13.0
Steps to Reproduce and Observed Behavior
In a freestanding platform, I'm trying to set the global pointer to some memory location, which I can reuse later in code. This is the simplified version of my program, that reproduces the problem:
along with the linker script:
When compiling this in
PIE
mode, the value used in the relocation table is set to 0:The 2nd value in the
.got
, which is the__global_pointer
variable, is set to0
.If I change the linker script to set
__global_pointer
to a constant value (e.g.0x80000000
), the variable is set:linker script:
executable content:
Expected Behavior
The
.got
should contain the correct address for__global_pointer
.