Skip to content

Commit a7ab308

Browse files
committed
[ld.lld] --gc-sections only when output is executable
When building object files, `zig cc` will instruct lld to remove unused sections via `--gc-sections`. This is problematic cgo builds that don't explicitly use C code. Briefly, go builds cgo executables as follows*: 1. build `_cgo_.o`, which links (on linux_amd64 systems) to `/usr/local/go/src/runtime/race/race_linux_amd64.syso`. 2. That `.syso` contains references to symbols from libc. If the user program uses at least one libc symbol, it will link correctly. However, if Go is building a cgo executable, but without C code, the sections from `.syso` file will be garbage-collected, leaving a `_cgo_.o` without any references to libc, causing the final linking step to not link libc. Until now, this could be worked around by `-linkmode external` flag to `go build`. This causes Go to link the final executable using the external linker (which implicitly links libc). However, that flag brings in a whole different world of worms. I assume the `gc_sections` is an optimization; I tried to re-add `--gc-sections` to the final executable, but that didn't go well. I know removing such an optimization may be contentious, so let's start the discussion here. Quoting @andrewrk in [1] (it was about `--as-needed`, but the point remains the same): > The C source code for the temporary executable needs to have dummy > calls to getuid, pthread_self, sleep, and every other libc function > that cgo/race code wants to call. I agree this is how it *should* work. However, while we could fix it for go, I don't know how many other systems rely on that, and we'll never know we've fixed the last one. The point is, GCC/Clang does not optimize sections by default, and downstream tools rely on that. If we want to consider `zig cc` a drop-in clang replacement (except for `-fsanitize=undefined`, which I tend to agree with), then it should not be optimizing the intermediate object files. Or at least have a very prominent fine-print that this is happening, with ways to work around it. Fixes #11398 Fixes golang/go#44695 Fixes golang/go#52690 [*]: Empirically observed with `CGO_ENABLED=1 go test -race -x -v` [1]: golang/go#52690 (comment)
1 parent 49a7ceb commit a7ab308

File tree

1 file changed

+1
-1
lines changed

1 file changed

+1
-1
lines changed

src/link/Elf.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1264,7 +1264,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
12641264
const have_dynamic_linker = self.base.options.link_libc and
12651265
self.base.options.link_mode == .Dynamic and is_exe_or_dyn_lib;
12661266
const target = self.base.options.target;
1267-
const gc_sections = self.base.options.gc_sections orelse !is_obj;
1267+
const gc_sections = self.base.options.gc_sections orelse false;
12681268
const stack_size = self.base.options.stack_size_override orelse 16777216;
12691269
const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os;
12701270
const compiler_rt_path: ?[]const u8 = blk: {

0 commit comments

Comments
 (0)