cmd/link: possible linker bug when using the -T flag to set the text address
#28,257 opened on Oct 17, 2018
Repository metrics
- Stars
- (133,883 stars)
- PR merge metrics
- (No merged PRs in 30d)
Description
Please answer these questions before submitting your issue. Thanks!
What version of Go are you using (go version)?
1.11.1 darwin/amd64
Does this issue reproduce with the latest release?
Yes.
What operating system and processor architecture are you using (go env)?
GOARCH="amd64"
GOBIN=""
GOCACHE="on"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/iansmith/qemu/xxx"
GOPROXY=""
GORACE=""
GOROOT="/Users/iansmith/qemu/go-1.11/go"
GOTMPDIR=""
GOTOOLDIR="/Users/iansmith/qemu/go-1.11/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="0"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/w0/fw3qzvvx54b39b790yxq6v100000gn/T/go-build145968613=/tmp/go-build -gno-record-gcc-switches -fno-common"
What did you do?
aarch64-elf-readelf -W -l -S bin/xxx_xxx/surprise
If possible, provide a recipe for reproducing the error.
I have found this error to be caused by any link that supplies an start address other than one ending in 0x1000. I was doing some experiments on arm (thus the aarch64 above) but I think this is actually in the offset calculations for the elf headers (section and program).
Commands like this seem to cause the problem (using the -T flag with something that doesn't end in 1000):
GOOS=xxx GOARCH=xxx go install -v -ldflags='-T 0x88000' github.com/iansmith/xxx/surprise/cmd/surprise
A complete runnable program is good. A link on play.golang.org is best.
https://play.golang.org/p/b32fVLNTGxP
That link shows the diff to my "fix". My fix is clearly not the real one, but whoever wrote the code in elf.go (go/src/cmd/link/internal/ld/elf.go) will probably see the problem immediately when they see what I have done.
What did you expect to see?
I expected to see normal elf section headers and program headers. After my (ahem) "fix", you get the normal output:
$ aarch64-elf-readelf -W -l -S bin/xxx_xxx/surprise
There are 24 section headers, starting at offset 0x158:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 0000000000088000 001000 03f8c0 00 AX 0 0 8
[ 2] .rodata PROGBITS 00000000000d0000 050000 024e79 00 A 0 0 32
[ 3] .shstrtab STRTAB 0000000000000000 074e80 000193 00 0 0 1
[ 4] .typelink PROGBITS 00000000000f5020 075020 000624 00 A 0 0 32
[ 5] .itablink PROGBITS 00000000000f5648 075648 000008 00 A 0 0 8
[ 6] .gosymtab PROGBITS 00000000000f5650 075650 000000 00 A 0 0 1
[ 7] .gopclntab PROGBITS 00000000000f5660 075660 0337c3 00 A 0 0 32
[ 8] .noptrdata PROGBITS 0000000000130000 0b0000 000ba8 00 WA 0 0 32
[ 9] .data PROGBITS 0000000000130bc0 0b0bc0 0015b0 00 WA 0 0 32
[10] .bss NOBITS 0000000000132180 0b2180 01a330 00 WA 0 0 32
[11] .noptrbss NOBITS 000000000014c4c0 0cc4c0 002258 00 WA 0 0 32
[12] .zdebug_abbrev PROGBITS 0000000000150000 0c0000 000112 00 0 0 8
[13] .zdebug_line PROGBITS 0000000000150112 0c0112 008fb1 00 0 0 8
[14] .zdebug_frame PROGBITS 00000000001590c3 0c90c3 0031ac 00 0 0 8
[15] .zdebug_pubnames PROGBITS 000000000015c26f 0cc26f 000973 00 0 0 8
[16] .zdebug_pubtypes PROGBITS 000000000015cbe2 0ccbe2 001cf1 00 0 0 8
[17] .debug_gdb_scripts PROGBITS 000000000015e8d3 0ce8d3 00003c 00 0 0 1
[18] .zdebug_info PROGBITS 000000000015e90f 0ce90f 015a44 00 0 0 8
[19] .zdebug_loc PROGBITS 0000000000174353 0e4353 009793 00 0 0 8
[20] .zdebug_ranges PROGBITS 000000000017dae6 0edae6 00309b 00 0 0 8
[21] .note.go.buildid NOTE 0000000000087f9c 000f9c 000064 00 A 0 0 4
[22] .symtab SYMTAB 0000000000000000 100000 006630 18 23 91 8
[23] .strtab STRTAB 0000000000000000 106630 006bf7 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
p (processor specific)
Elf file type is EXEC (Executable file)
Entry point 0xc4520
There are 5 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x0000000000087040 0x0000000000087040 0x000118 0x000118 R 0x10000
NOTE 0x000f9c 0x0000000000087f9c 0x0000000000087f9c 0x000064 0x000064 R 0x4
LOAD 0x000000 0x0000000000087000 0x0000000000087000 0x0408c0 0x0408c0 R E 0x10000
LOAD 0x057000 0x00000000000d7000 0x00000000000d7000 0x051e23 0x051e23 R 0x10000
LOAD 0x0b7000 0x0000000000137000 0x0000000000137000 0xffffffffffffb180 0x017718 RW 0x10000
readelf: Error: the segment's file size is larger than its memory size
Section to Segment mapping:
Segment Sections...
00
01 .note.go.buildid
02 .text .note.go.buildid
03 .typelink .itablink .gosymtab .gopclntab
04 .noptrbss
What did you see instead?
Note the negative value in the 3rd program header (the program text segment)! .shstrtab (section header string table) section has been overwritten so the names are garbage.
$ aarch64-elf-readelf -W -l -S bin/xxx_xxx/surprise
There are 24 section headers, starting at offset 0x158:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] ^B NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] PROGBITS 0000000000088000 001000 03f8c0 00 AX 0 0 8
[ 2] PROGBITS 00000000000d0000 050000 024e79 00 A 0 0 32
[ 3] STRTAB 0000000000000000 06de80 000193 00 0 0 1
[ 4] PROGBITS 00000000000f5020 075020 000624 00 A 0 0 32
[ 5] PROGBITS 00000000000f5648 075648 000008 00 A 0 0 8
[ 6] ^V PROGBITS 00000000000f5650 075650 000000 00 A 0 0 1
[ 7] PROGBITS 00000000000f5660 075660 0337c3 00 A 0 0 32
[ 8] PROGBITS 0000000000130000 0b0000 000ba8 00 WA 0 0 32
[ 9] PROGBITS 0000000000130bc0 0b0bc0 0015b0 00 WA 0 0 32
[10] ^B NOBITS 0000000000132180 0b2180 01a330 00 WA 0 0 32
[11] NOBITS 000000000014c4c0 0cc4c0 002258 00 WA 0 0 32
[12] ^B PROGBITS 0000000000150000 0c0000 000112 00 0 0 8
[13] PROGBITS 0000000000150112 0c0112 008fb1 00 0 0 8
[14] ^D PROGBITS 00000000001590c3 0c90c3 0031ac 00 0 0 8
[15] PROGBITS 000000000015c26f 0cc26f 000973 00 0 0 8
[16] ^E^A PROGBITS 000000000015cbe2 0ccbe2 001cf1 00 0 0 8
[17] PROGBITS 000000000015e8d3 0ce8d3 00003c 00 0 0 1
[18] PROGBITS 000000000015e90f 0ce90f 015a44 00 0 0 8
[19] PROGBITS 0000000000174353 0e4353 009793 00 0 0 8
[20] PROGBITS 000000000017dae6 0edae6 00309b 00 0 0 8
[21] NOTE 0000000000087f9c 000f9c 000064 00 A 0 0 4
[22] SYMTAB 0000000000000000 100000 006630 18 23 91 8
[23] STRTAB 0000000000000000 106630 006bf7 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
p (processor specific)
Elf file type is EXEC (Executable file)
Entry point 0xc4520
There are 5 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x0000000000087040 0x0000000000087040 0x000118 0x000118 R 0x10000
NOTE 0x000f9c 0x0000000000087f9c 0x0000000000087f9c 0x000064 0x000064 R 0x4
LOAD 0xffffffffffff9000 0x0000000000080000 0x0000000000080000 0x0478c0 0x0478c0 R E 0x10000
LOAD 0x050000 0x00000000000d0000 0x00000000000d0000 0x058e23 0x058e23 R 0x10000
LOAD 0x0b0000 0x0000000000130000 0x0000000000130000 0x002180 0x01e718 RW 0x10000
Section to Segment mapping:
Segment Sections...
00
01
02
03 ^V
04 ^B