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: wrong dynamic linker path when cross-compiling to OpenBSD #47760

Closed
ston1th opened this issue Aug 17, 2021 · 9 comments
Closed

cmd/link: wrong dynamic linker path when cross-compiling to OpenBSD #47760

ston1th opened this issue Aug 17, 2021 · 9 comments
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@ston1th
Copy link

ston1th commented Aug 17, 2021

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

$ go version
go version go1.17 linux/amd64

What did you do?

https://play.golang.org/p/HmnNoBf0p1z

I have cross compiled the above playground link from linux/amd64 to openbsd/amd64 using the following command:

$ GOOS=openbsd CGO_ENABLED=0 go build main.go

The resulting binary is not runnable on OpenBSD since the interpreter path has changed to a non-existing path:

$ file main
main: ELF 64-bit LSB executable, x86-64, version 1 (OpenBSD), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for OpenBSD, Go BuildID=vd3E-SlhI3tLFMvRBz4B/iBPYMJpGHeqsCumWHhW_/IDK-yv-c3x3Nd1JRa3cs/k9nxrvrFYgOMoo3NS6VO, not stripped

The path /lib64/ld-linux-x86-64.so.2 does not exist on OpenBSD - it should be /usr/libexec/ld.so

Here I'm trying to run the file on OpenBSD:

$ ./main
Abort trap 
$ ldd main
main:
main: signal 6

What did you expect to see?

Using go version 1.16.7 the interpreter path is the correct one (/usr/libexec/ld.so):

$ file main
main: ELF 64-bit LSB executable, x86-64, version 1 (OpenBSD), dynamically linked, interpreter /usr/libexec/ld.so, for OpenBSD, Go BuildID=XlJ8xxBBtSncSCQPbLgv/wez3LmpvHUCT5oLu-hUt/o-0-LIutWcnRHkDGtjwS/dXrqwwQwkP_TFSP6oU-x, not stripped

There is a workaround to run these programs on OpenBSD. One needs to create the /lib64 directory and in there a symlink to /usr/libexec/ld.so:

# mkdir /lib64
# ln -s /usr/libexec/ld.so /lib64/ld-linux-x86-64.so.2

After this is done the ldd command on OpenBSD works again:

$ ldd main                                             
main:
	Start            End              Type  Open Ref GrpRef Name
	0000000000400000 000000000057c000 exe   2    0   0      main
	00000002caadf000 00000002cabd4000 rlib  0    1   0      /usr/lib/libc.so.96.0
	000000024117a000 0000000241186000 rlib  0    1   0      /usr/lib/libpthread.so.26.1
	00000002f4cc1000 00000002f4cc1000 ld.so 0    1   0      /lib64/ld-linux-x86-64.so.2

And so does running the program:

$ ./main
Hello, playground
@jrick
Copy link
Contributor

jrick commented Aug 17, 2021

Untested, but building from Linux using

GOOS=openbsd CGO_ENABLED=0 go build -ldflags='-I /usr/libexec/ld.so' main.go

may workaround this issue.

@jrick
Copy link
Contributor

jrick commented Aug 17, 2021

This might be broken in general, and not specific to OpenBSD linking.

From OpenBSD, if I target illumos (because illumos builds also require dynamic linking, and they use the ELF format), it is using the openbsd dynamic linker path /usr/libexec/ld.so:

$ go version
go version go1.17 openbsd/amd64
$ cat main.go       
package main

import "fmt"

func main() {
        fmt.Println("Hello, playground")
}
$ GOOS=illumos CGO_ENABLED=0 go build main.go
$ readelf -l ./main

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

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x00000000000001f8 0x00000000000001f8  R      1000
  INTERP         0x0000000000000fed 0x0000000000400fed 0x0000000000400fed
                 0x0000000000000013 0x0000000000000013  R      1
      [Requesting program interpreter: /usr/libexec/ld.so]
  NOTE           0x0000000000000f88 0x0000000000400f88 0x0000000000400f88
                 0x0000000000000064 0x0000000000000064  R      4
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x00000000000985b0 0x00000000000985b0  R E    1000
  LOAD           0x0000000000099000 0x0000000000499000 0x0000000000499000
                 0x0000000000096938 0x0000000000096938  R      1000
  LOAD           0x0000000000130000 0x0000000000530000 0x0000000000530000
                 0x00000000000183e0 0x000000000004c5c0  RW     1000
  DYNAMIC        0x0000000000130020 0x0000000000530020 0x0000000000530020
                 0x0000000000000110 0x0000000000000110  RW     8
  TLS            0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000008  R      8
  LOOS+ffffffb   0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .note.go.buildid 
   03     .text .plt .interp .note.go.buildid 
   04     .rodata .rela.plt .gnu.version .hash .shstrtab .dynstr .dynsym .typelink .itablink .gopclntab 
   05     .go.buildinfo .dynamic .got.plt .noptrdata .data .bss .noptrbss 
   06     .dynamic 
   07     .tbss 
   08     

The -I linker flag appears to work.

$ GOOS=illumos CGO_ENABLED=0 go build -ldflags='-I /foo/ld.so' main.go      
$ readelf -l ./main                                                    

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

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x00000000000001f8 0x00000000000001f8  R      1000
  INTERP         0x0000000000000ff5 0x0000000000400ff5 0x0000000000400ff5
                 0x000000000000000b 0x000000000000000b  R      1
      [Requesting program interpreter: /foo/ld.so]
  NOTE           0x0000000000000f90 0x0000000000400f90 0x0000000000400f90
                 0x0000000000000064 0x0000000000000064  R      4
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x00000000000985b0 0x00000000000985b0  R E    1000
  LOAD           0x0000000000099000 0x0000000000499000 0x0000000000499000
                 0x0000000000096938 0x0000000000096938  R      1000
  LOAD           0x0000000000130000 0x0000000000530000 0x0000000000530000
                 0x00000000000183e0 0x000000000004c5c0  RW     1000
  DYNAMIC        0x0000000000130020 0x0000000000530020 0x0000000000530020
                 0x0000000000000110 0x0000000000000110  RW     8
  TLS            0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000008  R      8
  LOOS+ffffffb   0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .note.go.buildid 
   03     .text .plt .interp .note.go.buildid 
   04     .rodata .rela.plt .gnu.version .hash .shstrtab .dynstr .dynsym .typelink .itablink .gopclntab 
   05     .go.buildinfo .dynamic .got.plt .noptrdata .data .bss .noptrbss 
   06     .dynamic 
   07     .tbss 
   08     

@cherrymui
Copy link
Member

cherrymui commented Aug 17, 2021

Interesting. I cross-compile from macOS and do not get the same behavior. I think it might have something to do with make.bash now set GO_LDSO more aggressively.

@ston1th how do you install Go 1.17? Download from https://golang.org/dl or build from source? Thanks.

@cherrymui
Copy link
Member

Maybe we should ignore GO_LDSO if GOOS/GOARCH is not the same as host (but what happens with cross-compiling to a different machine with same architecture/OS?) Maybe we should use GO_LDSO only on Linux?

cc @ianlancetaylor

@jrick
Copy link
Contributor

jrick commented Aug 17, 2021

Cross compiling a PIE for Linux from OpenBSD also has the same issue.

@gopherbot
Copy link

Change https://golang.org/cl/343010 mentions this issue: cmd/link: do not use GO_LDSO when cross compile

@cherrymui cherrymui changed the title Wrong dynamic linker path when cross-compiling to OpenBSD cmd/link: wrong dynamic linker path when cross-compiling to OpenBSD Aug 18, 2021
@cherrymui
Copy link
Member

@gopherbot please backport this to Go 1.17. This is a regression. Thanks.

@gopherbot
Copy link

Backport issue(s) opened: #47782 (for 1.17).

Remember to create the cherry-pick CL(s) as soon as the patch is submitted to master, according to https://golang.org/wiki/MinorReleases.

@gopherbot
Copy link

Change https://golang.org/cl/343309 mentions this issue: [release-branch.go1.17] cmd/link: do not use GO_LDSO when cross compile

@dmitshur dmitshur added the NeedsFix The path to resolution is known, but the work has not been done. label Sep 1, 2021
@dmitshur dmitshur added this to the Go1.18 milestone Sep 1, 2021
gopherbot pushed a commit that referenced this issue Sep 1, 2021
GO_LDSO is a setting that is set when the toolchain is build. It
only makes sense to use it on the host platform. Do not use it
when targetting a different platform.

In the past it was not a problem as GO_LDSO was almost always
unset. Now, with CL 301989 it is almost always set (maybe we want
to revisit it).

Updates #47760.
Fixes #47782.

Change-Id: I2704b9968781f46e2d2f8624090db19689b1a32f
Reviewed-on: https://go-review.googlesource.com/c/go/+/343010
Trust: Cherry Mui <cherryyz@google.com>
Run-TryBot: Cherry Mui <cherryyz@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
(cherry picked from commit ddfcc02)
Reviewed-on: https://go-review.googlesource.com/c/go/+/343309
@golang golang locked and limited conversation to collaborators Sep 1, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

5 participants