aboutsummaryrefslogtreecommitdiff
path: root/src/link/Elf.zig
AgeCommit message (Collapse)Author
2025-10-29Elf2: start implementing dynamic linkingJacob Young
2025-10-27remove all Oracle Solaris supportAlex Rønne Petersen
There is no straightforward way for the Zig team to access the Solaris system headers; to do this, one has to create an Oracle account, accept their EULA to download the installer ISO, and finally install it on a machine or VM. We do not have to jump through hoops like this for any other OS that we support, and no one on the team has expressed willingness to do it. As a result, we cannot audit any Solaris contributions to std.c or other similarly sensitive parts of the standard library. The best we would be able to do is assume that Solaris and illumos are 100% compatible with no way to verify that assumption. But at that point, the solaris and illumos OS tags would be functionally identical anyway. For Solaris especially, any contributions that involve APIs introduced after the OS was made closed-source would also be inherently more risky than equivalent contributions for other proprietary OSs due to the case of Google LLC v. Oracle America, Inc., wherein Oracle clearly demonstrated its willingness to pursue legal action against entities that merely copy API declarations. Finally, Oracle laid off most of the Solaris team in 2017; the OS has been in maintenance mode since, presumably to be retired completely sometime in the 2030s. For these reasons, this commit removes all Oracle Solaris support. Anyone who still wishes to use Zig on Solaris can try their luck by simply using illumos instead of solaris in target triples - chances are it'll work. But there will be no effort from the Zig team to support this use case; we recommend that people move to illumos instead.
2025-09-30link.Elf: fix static PIEmlugg
We mustn't emit the DT_PLTGOT entry in `.dynamic` in a statically-linked PIE, because there's no dl to relocate it (and `std.pie.relocate`, or the PIE relocator in libc, won't touch it). In that case, there cannot be any PLT entries, so there's no point emitting the `.got.plt` section at all. If we just don't create that section, `link.Elf` already knows not to add the DT_PLTGOT entry to `.dynamic`. Co-authored-by: Jacob Young <jacobly0@users.noreply.github.com>
2025-09-08fix linker code writing undefined memory to the output fileAndrew Kelley
missing `extern` on a struct. but also all these instances that call pwriteAll with a `@ptrCast` are endianness bugs. this should be changed to use File.Writer and call writeSliceEndian instead. this commit fixes one immediate problem but does not fix everything.
2025-08-31std.fmt: delete deprecated APIsAndrew Kelley
std.fmt.Formatter -> std.fmt.Alt std.fmt.format -> std.Io.Writer.print
2025-08-29std.Io: delete GenericReaderAndrew Kelley
and delete deprecated alias std.io
2025-08-28link.Elf: update to not use GenericWriterAndrew Kelley
2025-08-25start adding big endian RISC-V supportAlex Rønne Petersen
The big endian RISC-V effort is mostly driven by MIPS (the company) which is pivoting to RISC-V, and presumably needs a big endian variant to fill the niche that big endian MIPS (the ISA) did. GCC already supports these targets, but LLVM support will only appear in 22; this commit just adds the necessary target knowledge and checks on our end.
2025-08-13std.io.Writer.Allocating: rename getWritten() to written()Isaac Freund
This "get" is useless noise and was copied from FixedBufferWriter. Since this API has not yet landed in a release, now is a good time to make the breaking change to fix this.
2025-08-11std.ArrayList: make unmanaged the defaultAndrew Kelley
2025-08-07std.Io: delete CountingWriterAndrew Kelley
2025-07-07std.fmt: fully remove format string from format methodsAndrew Kelley
Introduces `std.fmt.alt` which is a helper for calling alternate format methods besides one named "format".
2025-07-07compiler: update a bunch of format stringsAndrew Kelley
2025-07-07compiler: fix a bunch of format stringsAndrew Kelley
2025-07-07compiler: update all instances of std.fmt.FormatterAndrew Kelley
2025-06-19x86_64: increase passing test coverage on windowsJacob Young
Now that codegen has no references to linker state this is much easier. Closes #24153
2025-06-19Target: pass and use locals by pointer instead of by valueJacob Young
This struct is larger than 256 bytes and code that copies it consistently shows up in profiles of the compiler.
2025-06-12x86_64: remove air references from mirJacob Young
2025-06-12compiler: rework emit paths and cache modesmlugg
Previously, various doc comments heavily disagreed with the implementation on both what lives where on the filesystem at what time, and how that was represented in code. Notably, the combination of emit paths outside the cache and `disable_lld_caching` created a kind of ad-hoc "cache disable" mechanism -- which didn't actually *work* very well, 'most everything still ended up in this cache. There was also a long-standing issue where building using the LLVM backend would put a random object file in your cwd. This commit reworks how emit paths are specified in `Compilation.CreateOptions`, how they are represented internally, and how the cache usage is specified. There are now 3 options for `Compilation.CacheMode`: * `.none`: do not use the cache. The paths we have to emit to are relative to the compiler cwd (they're either user-specified, or defaults inferred from the root name). If we create any temporary files (e.g. the ZCU object when using the LLVM backend) they are emitted to a directory in `local_cache/tmp/`, which is deleted once the update finishes. * `.whole`: cache the compilation based on all inputs, including file contents. All emit paths are computed by the compiler (and will be stored as relative to the local cache directory); it is a CLI error to specify an explicit emit path. Artifacts (including temporary files) are written to a directory under `local_cache/tmp/`, which is later renamed to an appropriate `local_cache/o/`. The caller (who is using `--listen`; e.g. the build system) learns the name of this directory, and can get the artifacts from it. * `.incremental`: similar to `.whole`, but Zig source file contents, and anything else which incremental compilation can handle changes for, is not included in the cache manifest. We don't need to do the dance where the output directory is initially in `tmp/`, because our digest is computed entirely from CLI inputs. To be clear, the difference between `CacheMode.whole` and `CacheMode.incremental` is unchanged. `CacheMode.none` is new (previously it was sort of poorly imitated with `CacheMode.whole`). The defined behavior for temporary/intermediate files is new. `.none` is used for direct CLI invocations like `zig build-exe foo.zig`. The other cache modes are reserved for `--listen`, and the cache mode in use is currently just based on the presence of the `-fincremental` flag. There are two cases in which `CacheMode.whole` is used despite there being no `--listen` flag: `zig test` and `zig run`. Unless an explicit `-femit-bin=xxx` argument is passed on the CLI, these subcommands will use `CacheMode.whole`, so that they can put the output somewhere without polluting the cwd (plus, caching is potentially more useful for direct usage of these subcommands). Users of `--listen` (such as the build system) can now use `std.zig.EmitArtifact.cacheName` to find out what an output will be named. This avoids having to synchronize logic between the compiler and all users of `--listen`.
2025-06-12compiler: rework backend pipeline to separate codegen and linkmlugg
The idea here is that instead of the linker calling into codegen, instead codegen should run before we touch the linker, and after MIR is produced, it is sent to the linker. Aside from simplifying the call graph (by preventing N linkers from each calling into M codegen backends!), this has the huge benefit that it is possible to parallellize codegen separately from linking. The threading model can look like this: * 1 semantic analysis thread, which generates AIR * N codegen threads, which process AIR into MIR * 1 linker thread, which emits MIR to the binary The codegen threads are also responsible for `Air.Legalize` and `Air.Liveness`; it's more efficient to do this work here instead of blocking the main thread for this trivially parallel task. I have repurposed the `Zcu.Feature.separate_thread` backend feature to indicate support for this 1:N:1 threading pattern. This commit makes the C backend support this feature, since it was relatively easy to divorce from `link.C`: it just required eliminating some shared buffers. Other backends don't currently support this feature. In fact, they don't even compile -- the next few commits will fix them back up.
2025-06-12link: divorce LLD from the self-hosted linkersmlugg
Similar to the previous commit, this commit untangles LLD integration from the self-hosted linkers. Despite the big network of functions which were involved, it turns out what was going on here is quite simple. The LLD linking logic is actually very self-contained; it requires a few flags from the `link.File.OpenOptions`, but that's really about it. We don't need any of the mutable state on `Elf`/`Coff`/`Wasm`, for instance. There was some legacy code trying to handle support for using self-hosted codegen with LLD, but that's not a supported use case, so I've just stripped it out. For now, I've just pasted the logic for linking the 3 targets we currently support using LLD for into this new linker implementation, `link.Lld`; however, it's almost certainly possible to combine some of the logic and simplify this file a bit. But to be honest, it's not actually that bad right now. This commit ends up eliminating the distinction between `flush` and `flushZcu` (formerly `flushModule`) in linkers, where the latter previously meant something along the lines of "flush, but if you're going to be linking with LLD, just flush the ZCU object file, don't actually link"?. The distinction here doesn't seem like it was properly defined, and most linkers seem to treat them as essentially identical anyway. Regardless, all calls to `flushZcu` are gone now, so it's deleted -- one `flush` to rule them all! The end result of this commit and the preceding one is that LLVM and LLD fit into the pipeline much more sanely: * If we're using LLVM for the ZCU, that state is on `zcu.llvm_object` * If we're using LLD to link, then the `link.File` is a `link.Lld` * Calls to "ZCU link functions" (e.g. `updateNav`) lower to calls to the LLVM object if it's available, or otherwise to the `link.File` if it's available (neither is available under `-fno-emit-bin`) * After everything is done, linking is finalized by calling `flush` on the `link.File`; for `link.Lld` this invokes LLD, for other linkers it flushes self-hosted linker state There's one messy thing remaining, and that's how self-hosted function codegen in a ZCU works; right now, we process AIR with a call sequence something like this: * `link.doTask` * `Zcu.PerThread.linkerUpdateFunc` * `link.File.updateFunc` * `link.Elf.updateFunc` * `link.Elf.ZigObject.updateFunc` * `codegen.generateFunction` * `arch.x86_64.CodeGen.generate` So, we start in the linker, take a scenic detour through `Zcu`, go back to the linker, into its implementation, and then... right back out, into code which is generic over the linker implementation, and then dispatch on the *backend* instead! Of course, within `arch.x86_64.CodeGen`, there are some more places which switch on the `link` implementation being used. This is all pretty silly... so it shall be my next target.
2025-06-12compiler: slightly untangle LLVM from the linkersmlugg
The main goal of this commit is to make it easier to decouple codegen from the linkers by being able to do LLVM codegen without going through the `link.File`; however, this ended up being a nice refactor anyway. Previously, every linker stored an optional `llvm.Object`, which was populated when using LLVM for the ZCU *and* linking an output binary; and `Zcu` also stored an optional `llvm.Object`, which was used only when we needed LLVM for the ZCU (e.g. for `-femit-llvm-bc`) but were not emitting a binary. This situation was incredibly silly. It meant there were N+1 places the LLVM object might be instead of just 1, and it meant that every linker had to start a bunch of methods by checking for an LLVM object, and just dispatching to the corresponding method on *it* instead if it was not `null`. Instead, we now always store the LLVM object on the `Zcu` -- which makes sense, because it corresponds to the object emitted by, well, the Zig Compilation Unit! The linkers now mostly don't make reference to LLVM. `Compilation` makes sure to emit the LLVM object if necessary before calling `flush`, so it is ready for the linker. Also, all of the `link.File` methods which act on the ZCU -- like `updateNav` -- now check for the LLVM object in `link.zig` instead of in every single individual linker implementation. Notably, the change to LLVM emit improves this rather ludicrous call chain in the `-fllvm -flld` case: * Compilation.flush * link.File.flush * link.Elf.flush * link.Elf.linkWithLLD * link.Elf.flushModule * link.emitLlvmObject * Compilation.emitLlvmObject * llvm.Object.emit Replacing it with this one: * Compilation.flush * llvm.Object.emit ...although we do currently still end up in `link.Elf.linkWithLLD` to do the actual linking. The logic for invoking LLD should probably also be unified at least somewhat; I haven't done that in this commit.
2025-06-06x86_64: add support for pie executablesJacob Young
2025-06-06Elf: support non-comdat groupsJacob Young
I haven't actually found any documentation about these, but apparently groups aren't always comdats.
2025-05-29Legalize: introduce a new pass before livenessJacob Young
Each target can opt into different sets of legalize features. By performing these transformations before liveness, instructions that become unreferenced will have up-to-date liveness information.
2025-05-21link.Elf: Don't require linking libc for dynamic linker path to take effect.Alex Rønne Petersen
Closes #23813.
2025-05-17compiler: Support building NetBSD crt1.o/Scrt1.o and stub shared libraries.Alex Rønne Petersen
Only works for NetBSD 10.1+. Note that we still default to targeting NetBSD 9. Contributes to #2877.
2025-05-10compiler: Support building FreeBSD crt1.o/Scrt1.o and stub shared libraries.Alex Rønne Petersen
Only works for FreeBSD 14+. Note that we still default to targeting FreeBSD 13. Contributes to #2876.
2025-05-10compiler: Move vendored library support to `libs` subdirectory.Alex Rønne Petersen
2025-04-28Merge pull request #23663 from alexrp/emit-asm-onlyAlex Rønne Petersen
2025-04-28std.Target: Remove Os.Tag.elfiamcu.Alex Rønne Petersen
The last Intel Quark MCU was released in 2015. Quark was announced to be EOL in 2019, and stopped shipping entirely in 2022. The OS tag was only meaningful for Intel's weird fork of Linux 3.8.7 with a special ABI that differs from the regular i386 System V ABI; beyond that, the CPU itself is just a plain old P54C (i586). We of course keep support for the CPU itself, just not Intel's Linux fork.
2025-04-27link.Elf: Skip invoking LLD for `zig build-obj` for unsupported targets.Alex Rønne Petersen
LLD doesn't support these yet. Doing this hack will at least allow basic experimentation for these targets.
2025-04-13link: Improve handling of --build-id when using LLD.Alex Rønne Petersen
2025-04-11Introduce libzigc for libc function implementations in Zig.Alex Rønne Petersen
This lays the groundwork for #2879. This library will be built and linked when a static libc is going to be linked into the compilation. Currently, that means musl, wasi-libc, and MinGW-w64. As a demonstration, this commit removes the musl C code for a few string functions and implements them in libzigc. This means that those libzigc functions are now load-bearing for musl and wasi-libc. Note that if a function has an implementation in compiler-rt already, libzigc should not implement it. Instead, as we recently did for memcpy/memmove, we should delete the libc copy and rely on the compiler-rt implementation. I repurposed the existing "universal libc" code to do this. That code hadn't seen development beyond basic string functions in years, and was only usable-ish on freestanding. I think that if we want to seriously pursue the idea of Zig providing a freestanding libc, we should do so only after defining clear goals (and non-goals) for it. See also #22240 for a similar case.
2025-02-25move libubsan to `lib/` and integrate it into `-fubsan-rt`David Rubin
2025-02-17std.Target: Remove functions that just wrap component functions.Alex Rønne Petersen
Functions like isMinGW() and isGnuLibC() have a good reason to exist: They look at multiple components of the target. But functions like isWasm(), isDarwin(), isGnu(), etc only exist to save 4-8 characters. I don't think this is a good enough reason to keep them, especially given that: * It's not immediately obvious to a reader whether target.isDarwin() means the same thing as target.os.tag.isDarwin() precisely because isMinGW() and similar functions *do* look at multiple components. * It's not clear where we would draw the line. The logical conclusion before this commit would be to also wrap Arch.isX86(), Os.Tag.isSolarish(), Abi.isOpenHarmony(), etc... this obviously quickly gets out of hand. * It's nice to just have a single correct way of doing something.
2025-01-25link: Set machine and float ABI when invoking ld.lld and lld-link.Alex Rønne Petersen
If this isn't done, LTO can completely miscompile the input bitcode modules for certain targets where we need to explicitly set these ABIs (because LLVM's defaults are bad).
2025-01-15wasm linker: fix crashes when parsing compiler_rtAndrew Kelley
2025-01-15fix compilation when enabling llvmAndrew Kelley
2025-01-15compiler: add type safety for export indicesAndrew Kelley
2025-01-15rework error handling in the backendsAndrew Kelley
2025-01-15elf linker: conform to explicit error setsAndrew Kelley
2025-01-15macho linker conforms to explicit error sets, againAndrew Kelley
2025-01-15remove "FIXME" from codebaseAndrew Kelley
See #363. Please file issues rather than making TODO comments.
2025-01-15macho linker: conform to explicit error setsAndrew Kelley
Makes linker functions have small error sets, required to report diagnostics properly rather than having a massive error set that has a lot of codes. Other linker implementations are not ported yet. Also the branch is not passing semantic analysis yet.
2025-01-15wasm linker: aggressive DODificationAndrew Kelley
The goals of this branch are to: * compile faster when using the wasm linker and backend * enable saving compiler state by directly copying in-memory linker state to disk. * more efficient compiler memory utilization * introduce integer type safety to wasm linker code * generate better WebAssembly code * fully participate in incremental compilation * do as much work as possible outside of flush(), while continuing to do linker garbage collection. * avoid unnecessary heap allocations * avoid unnecessary indirect function calls In order to accomplish this goals, this removes the ZigObject abstraction, as well as Symbol and Atom. These abstractions resulted in overly generic code, doing unnecessary work, and needless complications that simply go away by creating a better in-memory data model and emitting more things lazily. For example, this makes wasm codegen emit MIR which is then lowered to wasm code during linking, with optimal function indexes etc, or relocations are emitted if outputting an object. Previously, this would always emit relocations, which are fully unnecessary when emitting an executable, and required all function calls to use the maximum size LEB encoding. This branch introduces the concept of the "prelink" phase which occurs after all object files have been parsed, but before any Zcu updates are sent to the linker. This allows the linker to fully parse all objects into a compact memory model, which is guaranteed to be complete when Zcu code is generated. This commit is not a complete implementation of all these goals; it is not even passing semantic analysis.
2025-01-05Added support for thin ltoTravis Lange
2025-01-05link: new incremental line number update APImlugg
2024-12-31link/Elf.zig: set stack size and build-id for dynamic libraries.Jan200101
2024-11-24std.Target: Add Os.HurdVersionRange for Os.Tag.hurd.Alex Rønne Petersen
This is necessary since isGnuLibC() is true for hurd, so we need to be able to represent a glibc version for it. Also add an Os.TaggedVersionRange.gnuLibCVersion() convenience function.