Questions on linking

200 views
Skip to first unread message

William Roberts

unread,
Sep 9, 2025, 12:59:18 PM (12 days ago) Sep 9
to golang-dev
So I am going through the golang code looking to enable BTI/PAC. Between the patches on Gerrit and some of my modifications, we're getting close. One thing I need to do is go through all the object files in linking and determine if each object file is annotated that it supports BTI.

lib.go/ldobj() seems to be important, it checks if it's an ELF, and calls ldhostobj which sets a function pointer callback to loadelf.Load(). However, I never see that callback invoked, but I see it get called for the archives in the build cache, but it never seems to load the individual object files to link them into the final executable. Are these linked externally or something? The linkmode is auto.

Thanks for any hints,
Bill

Cherry Mui

unread,
Sep 9, 2025, 9:06:30 PM (11 days ago) Sep 9
to golang-dev
With -linkmode=auto, in most cases when cgo is involved, the C objects are linked externally by default, i.e. by invoking the C linker. An exception is that if all the cgo-using packages are within a small set of known standard library packages such as net, os/user, runtime/cgo, or runtime/race, the default is internal linking. In particular, if any user package (non-standard library) uses cgo, it is linked externally by default.

So loadelf.Load is called only in this exceptional case, or when -linkmode=internal is set.

Cherry


William Roberts

unread,
Sep 10, 2025, 6:51:18 PM (11 days ago) Sep 10
to Cherry Mui, golang-dev
Thanks a million Cherry, if this all gets sent to the external linker, why do I see asmbElf called to write the ELF output?

Thanks,
Bill

--
You received this message because you are subscribed to a topic in the Google Groups "golang-dev" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-dev/oxDi-a2Xnyc/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-dev+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/golang-dev/1dfa1331-c2ed-437a-8169-0e56486a855fn%40googlegroups.com.

Cherry Mui

unread,
Sep 10, 2025, 10:52:54 PM (10 days ago) Sep 10
to William Roberts, golang-dev
I should have said it clearer: the external linking mode is the default for most of cgo linking. For pure-Go programs, internal linking is the default, where the Go linker writes out the executable without invoking the C linker. On ELF platforms, asmbElf is called to write the ELF executable in this case.

Even in external linking mode, asmbElf is also called, to write an ELF object (relocatable) file. The way it works is that the Go linker first links all Go packages (which are compiled to an internal Go-specific object file format) together, creates an ELF object file, and passes it to the C linker, along with the C object files to link with. In this mode, the Go linker doesn't load ELF objects (so loadelf.Load is not called) but does write an ELF object (so asmbElf is called).

In internal linking mode with cgo (which is used only in limited cases or when explicitly requested), the Go linker loads Go objects and C objects, and writes an ELF executable.

Cherry

William Roberts

unread,
Sep 11, 2025, 11:19:05 AM (10 days ago) Sep 11
to Cherry Mui, golang-dev
Ahh ok. Another question, when I look at the static archive produced in the build cache, it will often times have a few elf object files and then the "go object"  (you can see the magic check in the loader routine), is that go object format the linked collection of those elf objects or do they operate independently?

Bill

Cherry Mui

unread,
Sep 11, 2025, 10:14:30 PM (9 days ago) Sep 11
to William Roberts, golang-dev
The go objects and ELF objects in the build cache are "independent", in the sense that neither is a linked collection of the other. You can use "go build -x" to see what's being copied to the cache (clean the cache with "go clean -cache" if it is already cached and the build prints nothing). For example, for a cgo build, the runtime/cgo package will be built. The relevant lines are (# annotation mine)

# compiling C files
cd .../runtime/cgo
TERM='dumb' clang ... -o $WORK/b003/_x003.o -c gcc_context.c
TERM='dumb' clang ... -o $WORK/b003/_x004.o -c gcc_darwin_arm64.c
...
# compiling Go files
.../compile -o $WORK/b003/_pkg_.a ... -p runtime/cgo .../runtime/cgo/callbacks.go .../runtime/cgo/callbacks_traceback.go ...
# assemble Go assembly
.../asm -p runtime/cgo ... -o $WORK/b003/asm_arm64.o ./asm_arm64.s
# archive them together (go tool pack is like the system "ar" command)
go tool pack r $WORK/b003/_pkg_.a $WORK/b003/asm_arm64.o $WORK/b003/_x001.o $WORK/b003/_x002.o $WORK/b003/_x003.o $WORK/b003/_x004.o $WORK/b003/_x005.o $WORK/b003/_x006.o $WORK/b003/_x007.o $WORK/b003/_x008.o $WORK/b003/_x009.o $WORK/b003/_x010.o # internal
# copy the archive to cache
cp $WORK/b003/_pkg_.a .../Caches/go-build/d8/d8b2997627a1c8c5fe976863e4f7950f61456585ce92ae4fee1f108667f61785-d

The file being copied to the build cache is _pkg_.a, an archive containing Go object and C objects. (I'm running on Mac. It is similar on ELF platforms.)

For the "collection" ELF object in external linking mode which contains all Go packges in the program (the one mentioned in my previous email), it is just an intermediate file in the "link" action, and we don't cache it. In theory we could cache it, but probably not worth doing -- if any Go code in the program changes, we need to redo the linking.

Cherry


William Roberts

unread,
Sep 16, 2025, 12:27:35 PM (5 days ago) Sep 16
to Cherry Mui, golang-dev
Oops, missed reply all:

Thanks again Cherry, your responses have been very helpful in
clarifying the linking process. I have one, hopefully final, question.
With all these objects hanging around in the cache, is there a
possibility that changes introduced into the tool chain could be
linked against incompatible objects from a previous version of the
tool chain?

For instance, since this was all predicated on me looking at BTI
support, is there a possibility that an object built without BTI
support could be linked with an object with BTI support?

Hopefully my questions is clear, thanks again,
Bill

Ian Lance Taylor

unread,
Sep 16, 2025, 1:24:18 PM (5 days ago) Sep 16
to William Roberts, Cherry Mui, golang-dev
On Tue, Sep 16, 2025 at 9:27 AM William Roberts
<bill.c....@gmail.com> wrote:
>
> Thanks again Cherry, your responses have been very helpful in
> clarifying the linking process. I have one, hopefully final, question.
> With all these objects hanging around in the cache, is there a
> possibility that changes introduced into the tool chain could be
> linked against incompatible objects from a previous version of the
> tool chain?
>
> For instance, since this was all predicated on me looking at BTI
> support, is there a possibility that an object built without BTI
> support could be linked with an object with BTI support?

That can't happen for changes in the Go toolchain. For the C toolchain
part of the cache key for a package that uses cgo includes the C
compiler version number. So if you update the C toolchain _and change
version numbers_ then there won't be any problems, as all cgo packages
will be rebuilt. Also the flags passed to the C compiler are part of
the hash. But if you reconfigure the C toolchain in some way without
changing the version number or changing the flags that you pass, then,
yes, it is possible for there to be inconsistencies.

Ian

William Roberts

unread,
Sep 16, 2025, 1:34:11 PM (5 days ago) Sep 16
to Ian Lance Taylor, Cherry Mui, golang-dev
Thanks Ian, that is what I thought based on looking at the code, I
appreciate the
confirmation!
Reply all
Reply to author
Forward
0 new messages