cmd/link: do not reject addresses >= 2³¹ #7980
Closed
Labels
Milestone
Comments
All that's needed is to prevent the linker from stripping any of the arrays, so this suffices: func main() { _, _, _ = a[0], b[0], c[0] } Looks like a 32 bit overflow in the linker somewhere. Disassembly of main, array size 1 << 26: 0x0000000000002000 <+0>: mov 0x20075cc0,%rdx 0x0000000000002008 <+8>: mov 0x40075cc0,%rcx 0x0000000000002010 <+16>: mov 0x75cc0,%rbx 0x0000000000002018 <+24>: retq Disassembly of main, array size 1 << 27: 0x0000000000002000 <+0>: mov 0x40075cc0,%rdx 0x0000000000002008 <+8>: mov 0xffffffff80075cc0,%rcx 0x0000000000002010 <+16>: mov 0x75cc0,%rbx 0x0000000000002018 <+24>: retq |
Scratch the overflow comment. It appears that the 32 bit operand to MOV gets sign-extended by the processor. Note that the machine code does not contain 0xffffffff: 0x0000000000002000 <+0>: 48 8b 14 25 c0 5c 07 40 mov 0x40075cc0,%rdx 0x0000000000002008 <+8>: 48 8b 0c 25 c0 5c 07 80 mov 0xffffffff80075cc0,%rcx 0x0000000000002010 <+16>: 48 8b 1c 25 c0 5c 07 00 mov 0x75cc0,%rbx gdb disassembler's sign extension matches observed behavior--the panic is due to an attempt to dereference 0xffffffff80075cc0. It also matches http://onlinedisassembler.com/odaweb/iH4HYC/0. The two disassemblers I tried that do symbol resolution (Hopper.app and rsc's new x86 disassembler) incorrectly resolve this address to the main.c symbol. I think that we need to do relative addressing for addresses above 2**31. This might be a biggish change. It's also worth noting that this bug is not new -- it reproduces with Go 1.2. I'm going to stop working on this for now; my head hurts from wading through Intel's docs. |
for amd64, offsets are always signed, and also only 32-bit offset is offered. so to access address larger than 2^31-1, we need to first do a 64-bit literal load into a register and then indirectly load from that register. this might not be the only issue when the linker cannot handle 2GB+ data, so i think that we can defer it to 1.4. (although it's easy to fix this particular problem in liblink.) |
CL https://golang.org/cl/91500046 mentions this issue. |
Owner changed to @minux. Status changed to Started. |
This issue was updated by revision 6612983. This CL make the linker abort for the example program. For Go 1.4, we need to find a general way to handle large memory model programs. LGTM=dave, josharian, iant R=iant, dave, josharian CC=golang-codereviews https://golang.org/cl/91500046 Committer: Russ Cox |
Tangentially, rejecting 32-bit addresses >=2**31 means 6l can't link programs using the x86-64 kernel code model. Under that model, the program is loaded into the top 2GB of memory, so sign extending addresses is okay/desirable. I prepared a CL (https://golang.org/cl/117800044/) to change the "(int32)o < 0" check with "o != (int32)o", and also to change INITTEXT and INITDAT from int64 to uint64 (otherwise strtoll() caps the flags to LONG_MAX, and you can't specify an appropriate text address). With that CL, I'm able to successfully link a Go hello-world program using -ldflags='-T 0xffffffff80000c00', and it looks right if I inspect it with readelf. Of course, the Go runtime doesn't support running as a kernel, and no supported Go OS allows running userspace applications in this code model either, so it's perhaps moot. |
I think we basically decided this was okay. |
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
The text was updated successfully, but these errors were encountered: