Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/link: -T flag doesn't place text segment at specified address #58727

Closed
TotallyGamerJet opened this issue Feb 25, 2023 · 9 comments
Closed
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@TotallyGamerJet
Copy link

What version of Go are you using (go version)?

$ go version
go version go1.20.1 darwin/arm64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE="on"
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/jarrettkuklis/Library/Caches/go-build"
GOENV="/Users/jarrettkuklis/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/jarrettkuklis/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/username/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/Users/username/go/go1.20.1"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/Users/username/go/go1.20.1/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.20.1"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/username/Documents/GolandProjects/efi/go.mod"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/kw/8msl9lzx7wbdbq4xxtz3rhvr0000gn/T/go-build1473043980=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

Cross-compile an empty main function to linux with -R=0x1000 and -T=0x40000000 linker flags.

GOOS=linux go build -o a.out -ldflags="-R 0x1000 -T 0x40000000" ./test

What did you expect to see?

The text segment start at 0x40000000. (Example linked with +0xFFF)

$ readelf -Wl a.out

Elf file type is EXEC (Executable file)
Entry point 0x400535d0
There are 7 program headers, starting at offset 64

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  PHDR           0x000040 0x000000004000003f 0x000000004000003f 0x000188 0x000188 R   0x1000
  NOTE           0x000f9c 0x0000000040000f9b 0x0000000040000f9b 0x000064 0x000064 R   0x4
  LOAD           0x000001 0x0000000040000000 0x0000000040000000 0x054da0 0x054da0 R E 0x1000
  LOAD           0x055000 0x0000000040055000 0x0000000040055000 0x065098 0x065098 R   0x1000
  LOAD           0x0bb000 0x00000000400bb000 0x00000000400bb000 0x0034c0 0x03ac90 RW  0x1000
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x8
  LOOS+0x5041580 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000     0x8

 Section to Segment mapping:
  Segment Sections...
   00     
   01     note.go.buildid 
   02     text note.go.buildid 
   03     rodata typelink itablink gosymtab gopclntab 
   04     go.buildinfo noptrdata data bss noptrbss 
   05     
   06 

What did you see instead?

The text segment starts at 0x3FFFF000.

$ readelf -Wl a.out

Elf file type is EXEC (Executable file)
Entry point 0x400525d0
There are 7 program headers, starting at offset 64

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  PHDR           0x000040 0x000000003ffff040 0x000000003ffff040 0x000188 0x000188 R   0x1000
  NOTE           0x000f9c 0x000000003fffff9c 0x000000003fffff9c 0x000064 0x000064 R   0x4
  LOAD           0x000000 0x000000003ffff000 0x000000003ffff000 0x054da0 0x054da0 R E 0x1000
  LOAD           0x055000 0x0000000040054000 0x0000000040054000 0x065098 0x065098 R   0x1000
  LOAD           0x0bb000 0x00000000400ba000 0x00000000400ba000 0x0034c0 0x03ac90 RW  0x1000
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x8
  LOOS+0x5041580 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000     0x8

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .note.go.buildid 
   02     .text .note.go.buildid 
   03     .rodata .typelink .itablink .gosymtab .gopclntab 
   04     .go.buildinfo .noptrdata .data .bss .noptrbss 
   05     
   06 
@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Feb 25, 2023
@thanm thanm added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Feb 27, 2023
@thanm
Copy link
Contributor

thanm commented Feb 27, 2023

@thanm @cherrymui

@thanm
Copy link
Contributor

thanm commented Feb 27, 2023

Looks as though what's happening here

https://go.googlesource.com/go/+/fcfbbf2ff68a8997438d82cc2800c4744e908854/src/cmd/link/internal/ld/elf.go#1846

is that the linker is taking the specified -T value and then subtracting off HEADR, which is set to ELFRESERVE here:

https://go.googlesource.com/go/+/fcfbbf2ff68a8997438d82cc2800c4744e908854/src/cmd/link/internal/ld/elf.go#167

Perhaps the intent for "-T" was to ensure that the address of the first actual function in the text segment is set to the specified value? It's hard to tell.

@cherrymui let me know if you know the history behind this.

@TotallyGamerJet
Copy link
Author

Perhaps the intent for "-T" was to ensure that the address of the first actual function in the text segment is set to the specified value? It's hard to tell.

If that is the case, that seems to be the wrong behavior since the docs say that "-T" sets the address of the segment.

@cherrymui
Copy link
Member

I don't know the history behind this. It seems it has been like so (after the header, not before) since the beginning.

Manually using flags like this is not generally supported, and the meaning of the flag is not accurately specified, especially given that (at least on some platforms) the header is part of the text segment. Since it's been so for a long time, I think we just document that -T means the start address of text symbols.

@cherrymui cherrymui added this to the Unplanned milestone Feb 27, 2023
@thanm
Copy link
Contributor

thanm commented Feb 27, 2023

I agree with @cherrymui.

I might add that when I look at similar functionality with clang/lld, it also doesn't line up exactly on the dot at 0x40000000:

$ clang-14 himom.c -Wl,-Ttext-segment=0x40000000
$ readelf -Wl a.out
...
Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  PHDR           0x000040 0x0000004000000040 0x0000004000000040 0x0002d8 0x0002d8 R   0x8
  INTERP         0x000318 0x0000004000000318 0x0000004000000318 0x00001c 0x00001c R   0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x000000 0x0000004000000000 0x0000004000000000 0x000648 0x000648 R   0x1000
  LOAD           0x001000 0x0000004000001000 0x0000004000001000 0x000175 0x000175 R E 0x1000
  LOAD           0x002000 0x0000004000002000 0x0000004000002000 0x0000e4 0x0000e4 R   0x1000
  LOAD           0x002dc0 0x0000004000003dc0 0x0000004000003dc0 0x000258 0x000260 RW  0x1000
  DYNAMIC        0x002dd0 0x0000004000003dd0 0x0000004000003dd0 0x0001f0 0x0001f0 RW  0x8
...
$

@TotallyGamerJet
Copy link
Author

Like you mentioned using the flags isn't often used. However, they do exist to be used, no? If so, having "-T" specify the start of the elf header is prolly best. It means that it's possible to load the segment at the beginning of a memory page. Which is my use case.

I'm not familiar with PE and Mach-O but does link have equivalent behavior of specifying the start of the text symbol on these?

@TotallyGamerJet
Copy link
Author

I might add that when I look at similar functionality with clang/lld, it also doesn't line up exactly on the dot at 0x40000000:

Is this not because the the text symbol is being placed after the read only data? Because if a linker script was used to place the text symbol first it would be aligne. Since lld did place rodata at the specified address.

@ianlancetaylor
Copy link
Contributor

The current behavior of -T dates back to at least https://golang.org/cl/158041 from 2009, so I don't think we are going to change it now.

The GNU linker has a similar confusion about -T, which it calls -Ttext, because the flag was introduced in the days of the a.out format where it made sense. The GNU linker now has both --Ttext and -Ttext-segment options to reduce the confusion.

@gopherbot
Copy link

Change https://go.dev/cl/472356 mentions this issue: cmd/link: update -T flag's documentation

@golang golang locked and limited conversation to collaborators Feb 29, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

5 participants