How do disable vDSO for i386 and use linker script?

70 views
Skip to first unread message

evan.me...@gmail.com

unread,
Aug 11, 2020, 11:12:38 AM8/11/20
to golang-nuts
I am attempting to build a simple hello-world go program for a custom operating system that provides compatibility with a subset of Linux syscalls through the INT 0x80 syscall inferface.

My understanding is that go uses the Linux vDSO for time functions, but that otherwise it uses INT 0x80 for syscalls. What I am not 100% sure of is whether go automatically uses INT 0x80 on i386 if the kernel does not provide a pointer to the vDSO in the aux vector. I found this issue on the tracker, but it addresses amd64 instead of i386.


1. Is it possible to completely disable use of the vDSO for i386/Linux programs? If so, is this done at build time, or automatically by the go runtime?


Secondly, I need to use a custom linking script to build my program so that it can be loaded into the user address space designated by the OS. I tried doing this with the following command, but this seems to have linked my hello-world program with glibc code and introduced gratuitous usage of the vDSO via CALL *%gs:0x10.


CGO_ENABLED=0 GOARCH=386 go tool link -v -linkmode external -extldflags "-static -Ti386.ld" hello.o


2. Is it possible to feed a linker script into the default go linker similar to gcc's "-T" option?

3. Is it possible to link go programs using gcc without also linking in glibc code? The command above generates the host link command below, which seems to link lpthread.

One idea I had for this is to use the gccgo front end to compile the program under the assumption that I will be able to have more control over the linker flags since the assembler will output a standard object file instead of go's proprietary format. Is there merit to this approach?


I am also curious why lpthread is linked at all when using -linkmode external. I thought that the go runtime provided its own threading implementation, making lpthread unnecessary. It's also unclear to my why glibc code would be linked in considering that CGO_ENABLED=0 is set. Am I misunderstanding what the linker is doing here?


Thanks in advance,
Evan

Ian Lance Taylor

unread,
Aug 11, 2020, 2:05:46 PM8/11/20
to evan.me...@gmail.com, golang-nuts
On Tue, Aug 11, 2020 at 8:12 AM <evan.me...@gmail.com> wrote:
>
> I am attempting to build a simple hello-world go program for a custom operating system that provides compatibility with a subset of Linux syscalls through the INT 0x80 syscall inferface.
>
> My understanding is that go uses the Linux vDSO for time functions, but that otherwise it uses INT 0x80 for syscalls. What I am not 100% sure of is whether go automatically uses INT 0x80 on i386 if the kernel does not provide a pointer to the vDSO in the aux vector. I found this issue on the tracker, but it addresses amd64 instead of i386.

The same thing happens on 386 GNU/Linux. If the VDSO is not found at
program startup time, because there is no AT_SYSINFO_EHDR aux value,
then the runtime will fall back to using int 0x80.


> 1. Is it possible to completely disable use of the vDSO for i386/Linux programs? If so, is this done at build time, or automatically by the go runtime?

There is no way to disable use of the VDSO if it is present on the system.


> Secondly, I need to use a custom linking script to build my program so that it can be loaded into the user address space designated by the OS. I tried doing this with the following command, but this seems to have linked my hello-world program with glibc code and introduced gratuitous usage of the vDSO via CALL *%gs:0x10.
>
>
> CGO_ENABLED=0 GOARCH=386 go tool link -v -linkmode external -extldflags "-static -Ti386.ld" hello.o

This will link against libc, but I wouldn't expect it to actually use
anything from libc. Where are the VDSO references coming from?


> 2. Is it possible to feed a linker script into the default go linker similar to gcc's "-T" option?

No. You can use the -T option to set the text segment address, but
there is no support for general linker scripts.


> 3. Is it possible to link go programs using gcc without also linking in glibc code? The command above generates the host link command below, which seems to link lpthread.

I don't think so, at least not easily. Once you invoke the external
linker, it's going to expect to use the glibc startup code.


> One idea I had for this is to use the gccgo front end to compile the program under the assumption that I will be able to have more control over the linker flags since the assembler will output a standard object file instead of go's proprietary format. Is there merit to this approach?

Yes, that is likely true.

> I am also curious why lpthread is linked at all when using -linkmode external. I thought that the go runtime provided its own threading implementation, making lpthread unnecessary. It's also unclear to my why glibc code would be linked in considering that CGO_ENABLED=0 is set. Am I misunderstanding what the linker is doing here?

The external linker normally expects that you are using cgo. When
using cgo, threads are created using pthread_create. Only when not
using cgo, and not using glibc, does the Go runtime use the clone
system call directly.

Ian

evan.me...@gmail.com

unread,
Aug 11, 2020, 3:26:31 PM8/11/20
to golang-nuts
Thanks, Ian - this is very helpful.

To address your question - the VDSO references all appear to be associated with libc. There are 284 `call *%gs:0x10` instructions in the binary. I haven't looked at all of them, but the ones that I have reviewed are inside libc symbols. Stepping over the program, the first time the VDSO is used is inside __geteuid, which is called by __libc_init_secure. 

The call graph looks like this:

_start -> __libc_start_main -> __libc_init_secure -> __geteuid


I also have a quick follow up question based on #1 here:

>> 1. Is it possible to completely disable use of the vDSO for i386/Linux programs? If so, is this done at build time, or automatically by the go runtime? 

>There is no way to disable use of the VDSO if it is present on the system.

The VDSO is not present on my target OS, but it is present on the OS building the binary, which is amd64 Linux compiling for i386 Linux. To your knowledge, is there anything that I need to do so that VDSO is not used by a pure go program compiled with the standard toolchain? Will the go runtime detect the absence of AT_SYSINFO_EHDR in the aux vector at runtime and use INT 0x80 instead?

Thanks,
Evan

Ian Lance Taylor

unread,
Aug 11, 2020, 3:40:51 PM8/11/20
to evan.me...@gmail.com, golang-nuts
On Tue, Aug 11, 2020 at 12:26 PM <evan.me...@gmail.com> wrote:
>
> I also have a quick follow up question based on #1 here:
>
> >> 1. Is it possible to completely disable use of the vDSO for i386/Linux programs? If so, is this done at build time, or automatically by the go runtime?
>
> >There is no way to disable use of the VDSO if it is present on the system.
>
> The VDSO is not present on my target OS, but it is present on the OS building the binary, which is amd64 Linux compiling for i386 Linux. To your knowledge, is there anything that I need to do so that VDSO is not used by a pure go program compiled with the standard toolchain? Will the go runtime detect the absence of AT_SYSINFO_EHDR in the aux vector at runtime and use INT 0x80 instead?

Yes: if there is no AT_SYSINFO_EDHR at runtime, the Go runtime will
use int 0x80 for all system calls. This is independent of whether the
VDSO exists at build time.

Ian
Reply all
Reply to author
Forward
0 new messages