Commit Graph

3496 Commits

Author SHA1 Message Date
Kendall Condon e1ce81eb54 link.Elf: fix large abi aligned globals 2026-05-25 18:37:23 -07:00
Matthew Lugg fec502ec67 Elf2: flush ehdr phoff when rodata moves
I should have realised what was going on here sooner, because it was
really simple! We had a file offset which was being flushed in
`flushMoved` instead of `flushFileOffset`, and since `flushMoved` does
not bubble down to the PHDR segment from the "parent" read-only LOAD
segment, we weren't updating `ehdr.phoff` if the rodata segment had to
move. The tricky thing which meant I didn't catch this sooner is that
this wasn't happening on all filesystems, because the behavior of
`link.MappedFile` differs depending on the capabilities of the target
filesystem.

Resolves: https://codeberg.org/ziglang/zig/issues/32123
Resolves: https://codeberg.org/ziglang/zig/issues/35367
2026-05-20 10:40:11 +01:00
Anders Stenberg 9ba4552793 Elf2: avoid overflow in shentsize * shnum calculations 2026-05-17 18:55:27 +01:00
Matthew Lugg 97fe49a80f Elf2: rework the symtab, and fix a bunch of stuff
Sorry for the mega-commit, this diff got a little out of control.

The main thing here is a complete rework of how Elf2 handles the symbol
table. I messed around with the design for a while and landed on
something which is fairly memory-efficient (in particular the overhead
for STB_LOCAL symbols is as low as possible) and fulfils some of the
more awkward constraints of the ELF format. The main such constraint is
that all STB_LOCAL symbols in a symbol table are required to appear
before any STB_GLOBAL/STB_WEAK symbols. This is further complicated by
the fact that when producing a DSO, symbols with STV_HIDDEN or
STV_INTERNAL visibility are required to have STB_LOCAL binding in the
symbol table, even though they are global symbols from the perspective
of the link editor. Plus, when combining multiple symbols with the same
name, the resulting visibility is the strictest of all of the inputs, so
it is possible at any point in compilation to discover an extern/export
symbol which forces an existing STB_GLOBAL symbol to become STB_LOCAL
and therefore requires it to move to an earlier symtab index. Dealing
with all of this was quite awkward.

But I got there! I also implemented a lot of features in the process. I
don't remember everything perfectly, but here's a vague list:

* Multiple definitions of and/or unresolved references to symbols are
  now combined correctly in all cases

* `.bss` sections from inputs are correctly lowered (we don't actually
  emit a `.bss` section of our own yet, but I was able to put that data
  into the `.data` section so that the functionality is correct)

* Relocations in link inputs are now always processed (previously they
  would be silently ignored in most cases)

* Linker errors are triggered if a supported input section has a
  relocation which targets an unsupported input section (previously
  the unsupported section's symbol was dropped and associated
  relocations would be silently ignored)

* When linking a static executable, an error is emitted if a required
  symbol (i.e. an undefined reference with strong linkage) was never
  defined

* Duplicate symbol errors now work correctly

* When emitting a relocatable, the offsets of relocation entries are now
  correct (previously the offsets written were relative to a symbol
  rather than a section, meaning that e.g. almost all text relocations
  were just in a single function)

The changes in all of the other linkers and codegen backends are some
added type-safety at the codegen-linker API boundary. There are now
distinct `u32`-backed types for identifying an "atom" (the thing we're
codegenning) and a "symbol" (the thing which a relocation targets).
Linker implementations can use a couple of private helper functions to
convert between this implementation-agnostic type and their specific
type; for instance, `Elf2` can convert between a `Symbol.Id` and a
`link.File.SymbolId` with `Symbol.Id.fromTypeErased` and
`Symbol.Id.toTypeErased`. I didn't implement this nicely for any other
linker, so right now there's a lot of `@enumFromInt`/`@intFromEnum`
sprinkled all over the place, particularly with the legacy ELF and
Mach-O linkers.

I tested that I could still perform incremental updates to the Zig
compiler using this commit. In terms of the new behaviors, the most
interesting stuff is symbol and relocation resolution, so I ran a few
tests involving building a "Hello World" binary in various different
ways:

* `build-exe` correctly succeeds

* `build-exe -fno-compiler-rt` correctly reports undefined symbols

* `build-obj` linked with `build-exe` correctly succeeds

* `build-obj` linked with `build-exe -fno-compiler-rt` correctly reports
  undefined symbols

* `build-obj -fcompiler-rt` linked with `build-exe -fno-compiler-rt`
  correctly succeeds

* `build-obj -fcompiler-rt` linked with `build-exe` correctly succeeds
  (the compiler-rt symbols are weak so the global symbols are
  arbitrarily resolved to one of the two implementations)

I also manually verified with `readelf` that symbol tables were always
ordered correctly (before this PR, `readelf -s` would usually emit
warnings about incorrectly-ordered symtabs!), and verified that various
visibility attributes worked as expected.

No actual test coverage is added due to the current lack of a useful
linker test harness. Once a good test harness is available I will be
willing to write some tests.
2026-05-17 18:55:26 +01:00
Matthew Lugg e8ef01f222 Elf2: fix expected_nodes_len calculation
I'm not sure what the basis was for the old logic here, but it was
incorrect and caused an assertion failure in some cases. The
dependencies on `maybe_interp` and `any_non_single_threaded` are already
correctly modeled by `phnum`, so do not need to be accounted for a
second time.
2026-05-17 18:08:58 +01:00
Matthew Lugg 65c3a07709 Elf2: don't try to add needed dso in relocatable 2026-05-17 18:08:58 +01:00
Matthew Lugg 2ec0b886a2 Elf2: allow more EI_OSABI values in inputs
On Linux, the OSABI field can be either ELFOSABI_GNU or ELFOSABI_NONE
(aka ELFOSABI_SYSV). Therefore, even if we have chosen ELFOSABI_GNU, we
still need to accept ELFOSABI_NONE in link inputs.

Then, since we're now having to check the ident componentwise anyway, we
may as well give more precise error messages on mismatch.
2026-05-17 18:08:58 +01:00
Matthew Lugg 55cdf6c28b std.elf: add Ident struct
This is much nicer than indexing a raw 16-byte buffer.
2026-05-17 18:08:57 +01:00
Andrew Kelley 3d56df1716 Merge pull request 'std.fmt, std.mem.Allocator: Remove bufPrintZ()/dupeZ() in favor of bufPrintSentinel()/dupeSentinel()' (#35190) from linus/zig:deprecated-std-fmt-mem into master
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/35190
Reviewed-by: Andrew Kelley <andrew@ziglang.org>
2026-05-06 19:34:52 +02:00
Linus Groh fcc0a5a913 std.mem.Allocator: Remove dupeZ() in favor of dupeSentinel() 2026-05-03 21:42:16 +01:00
Matthew Lugg 4c330e053b compiler: use 'std.lang' instead of 'std.builtin' 2026-05-03 12:23:30 +01:00
Matthew Lugg fdac89d6cd remove uses of array multiplication
In preparation for its removal as accepted in
https://github.com/ziglang/zig/issues/24738.
2026-04-30 08:57:51 +01:00
Alex Rønne Petersen 0227253677 compiler: link libtsan with -whole-archive
libtsan contains a .preinit_array entry that must run for correctness.
2026-04-29 13:01:33 +02:00
Alex Rønne Petersen 3906434746 link.Elf: implement .preinit_array support 2026-04-28 16:42:06 +02:00
Alex Rønne Petersen 89ed51bf53 link.Elf, link.Lld: executables should not have an image base on Haiku
Executables are always ET_DYN on Haiku, so like shared libraries, they should
not have an image base set. Elf2 already got this right, but Elf and Lld didn't.

closes https://codeberg.org/ziglang/zig/issues/32100
2026-04-28 09:56:53 +02:00
GasInfinity 1deb029a66 std: rename bit_set variants and deprecate the managed one.
* aliases and deprecates the previous names.
* also update callsites to use the non-deprecated declarations.
2026-04-27 16:46:26 +02:00
Alex Rønne Petersen 1be84a39b8 compiler: fix and simplify DllMainCRTStartup handling
See: https://github.com/llvm/llvm-project/pull/171680
2026-04-25 21:54:48 +02:00
Alex Rønne Petersen 4c50c4b6e5 llvm: wire up the xtensa backend
As of LLVM 22, it can produce assembly and object files. No LLD support,
however, so using it is still a bit of a pain.
2026-04-25 21:54:47 +02:00
Alex Rønne Petersen ca0b3318a0 std.Target: update CPU and feature data to LLVM 22 2026-04-25 21:54:47 +02:00
andrew.kraevskii bbab366b78 Audit usages of toOwnedSlice (#32001)
Followup to #30769

I grepped for `try .*toOwnedSlice` and checked all of them by hand.

Fixes a bunch of memory leaks removes usages or `errdefer` and `vars` in some places. I also switched array_list.Managed to ArrayList where it was convenient.

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/32001
Reviewed-by: Andrew Kelley <andrew@ziglang.org>
2026-04-22 19:35:46 +02:00
rpkak 9df02121d0 link.Elf: support R_X86_64_PC64 2026-04-22 19:15:18 +02:00
Pavel Verigo 22945fbbdc stage2-wasm: vector, std tests 2026-04-22 00:19:46 +02:00
Ryan Liptak 3252a05531 Prefer <err> => |e| return e over <err> => return <err>
Avoids the potential for a typo on the `return <err>` side of the prong
2026-04-20 18:03:14 -07:00
Mason Remaley e2c3920fb1 Renames buffer first allocator in compiler and std 2026-04-18 14:51:49 -07:00
Mason Remaley 8c96487bb9 Updates all uses of StackFallbackAllocator 2026-04-18 14:51:49 -07:00
David Gonzalez Martin 37a20d3984 Allow the user to override unexpected error trace
This is the only bit left in the standard library where stack trace writing
code is pulled to the binary even if the user doesn't want it
2026-04-13 19:58:01 +02:00
Alex Rønne Petersen d6f43caadf Merge pull request 'audit: handle process.Child.Term exhaustively and give useful exit information on process exit' (#31018) from murtaza/zig:child.term-audit into master
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31018
Reviewed-by: Alex Rønne Petersen <alex@alexrp.com>
2026-04-11 00:59:11 +02:00
Andrew Kelley c3a862522b std: remove managed array hash map variants
And deprecate all the API names except for:
* `std.array_hash_map.Auto`
* `std.array_hash_map.String`
* `std.array_hash_map.Custom`
2026-04-10 17:39:45 +02:00
murtaza 4a1383d987 process.Child: use std.posix.SIG instead of u32 for Child.Term stopped field 2026-04-07 10:27:21 +02:00
Pavel Verigo ad7a028228 stage2-wasm: pass incremental tests
This PR enables all incremental tests under the `test/incremental` directory, except one: `change_exports`, which is currently ignored as it requires a non-trivial amount of work on the linker, since we do not currently support exporting data symbols.

To enable the other tests, the following fixes were needed:

1. `src/link/Wasm.zig`: instead of chasing function type through Nav, get it directly.
2. `src/target.zig`: `.panic_fn` appears to work fine with the wasm backend.
3. `src/codegen/wasm/CodeGen.zig`: there was a liveness related bug that caused some `ArenaAllocator` code to crash the backend.

More info on (3), the liveness and local reuse code in the backend for years in unfinished state. For example there is currently no branch merging and reuse happens only when inst die in same block level. I initially considered doing a large refactor to implement everything correctly, but aborted due to its sheer size and currently! no clear idea about how to do this efficiently.

Instead, I fixed the bug with minimal changes and removed useless code, keeping the old solution otherwise intact.
2026-04-04 15:21:35 +02:00
Matthew Lugg fca3f6f62e MachO: don't split subsections on N_ALT_ENTRY symbols
MachO has a mechanism where symbols can introduce "subsections", which
(as I understand it) allows a linker to garbage-collect parts of
sections without pulling in the heavy machinery of `-fdata-sections` and
`-ffunction-sections`. Essentially, symbols can be considered to
partition a section, and these boundaries are not allowed to be crossed
by memory accesses, so the linker can detect symbols which are unused
and drop the corresponding input section regions.

However, the symbol flag `N_ALT_ENTRY` indicates that a symbol should
not participate in this "splitting", and is instead an "alternate entry
point" to the previous subsection, which should continue through this
symbol.

The Mach-O linker was failing to ignore `N_ALT_ENTRY` symbols when
creating subsections, which meant that for certain link inputs, it would
create additional subsection splits, and then garbage collect the extra
sections (due to the `N_ALT_ENTRY` symbol being unused). Naturally, this
silent dropping of parts of input sections led to miscompilations.
2026-03-28 16:50:43 +00:00
Pavel Verigo 6ed9c05210 link.Wasm: fix indirect function table handling
The changes to the LLVM backend here changed the compiler_rt object
which LLVM emits, and exposed some buggy behavior in the self-hosted
WASM linker when parsing that object.
2026-03-28 16:50:43 +00:00
Alex Rønne Petersen 13b1050d4c link.MachO.Dylib: allow aarch64-macos to match arm64e-macos TBD entries
closes https://codeberg.org/ziglang/zig/issues/31658
2026-03-26 08:48:38 +01:00
squidy239 4c3877069d remove various workarounds for issues that are now fixed (#31567)
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31567
Reviewed-by: Andrew Kelley <andrew@ziglang.org>
Co-authored-by: squidy239 <sachabarsayuracko@gmail.com>
Co-committed-by: squidy239 <sachabarsayuracko@gmail.com>
2026-03-20 19:58:33 +01:00
Antonin Décimo 83add375c4 zld: fix null dereference parsing Mach-O non-existing atom or FDE
If the unwind record address has not been added to
`superposition` (maybe it is not in the current symbol table mapping?)
then there's a panic on null dereference. Ensure the entry exists in
`superposition`.
2026-03-18 00:45:50 +01:00
Nicholas McDaniel d3fcfb0581 linker: Don't copy protected visibility from shared object symbols
Resolves #30081
2026-03-16 23:01:55 +01:00
Leon Lombar badd252036 link(ELF): add ZSTD decompression support for compressed sections 2026-03-16 22:57:02 +01:00
Matthew Lugg 5d215838a7 InternPool.Nav: fix race, refactor
I've realised that the cause of at least some of our weird CI flakiness
was a bug in how `Nav` values were resolved. Consider this scenario: the
frontend resolves the type of a `Nav`, and then sends a function to the
backend, which requires the backend to lower a pointer to that `Nav`.
The backend calls `InternPool.getNav` to determine the `Nav`'s type.
However, this races with the frontend resolving the *value* of that
`Nav`. This involves writing separately to two fields, `bits` and
`type_or_value`. If only one of these changes is observed, then the
backend will incorrectly interpret the type as the value or vice versa,
leading to a crash or even a miscompilation. (Of course, there's also
the straightforward issue that the racing loads were non-atomic, making
them illegal).

The only good solution to this was to make `Nav` 4 bytes bigger, giving
it separate `type` and `value` fields. In theory that's a quite small
change, but it ended up having a bunch of nice consequences which led to
this diff being a bit bulkier than expected:

* `Nav.Repr.Bits` was simplified, because it no longer has to track
  "resolution status": we can use `.none` for that. This frees up some
  bits to make things more consistent between the "type resolved" and
  "fully resolved" states.

* This consistency allowed the `Nav.status` union to be replaced with a
  simpler field `Nav.resolved`, which is a bit nicer to work with.

* Most of the "getter" functions were able to be removed from `Nav`
  because the state they were fetching had been moved to simple fields
  on `Nav.resolved`.

* There were still a handful of free bits in `Nav.Repr.Bits`, which
  could be used to represent the "const" and "threadlocal" flags rather
  than these being stored on `Key.Extern` and `Key.Variable`. This is a
  bit more convenient for linkers.

* With those bits gone, `Key.Variable` is a trivial wrapper around a
  type and an initial value, and the fact that a declaration is mutable
  can be represented solely through the "const" flag. Therefore,
  `Key.Variable` no longer served a purpose, and could be eliminated
  entirely in favour of storing the variable's initial value directly in
  the "value" field of the `Nav`.

So, I'm quite pleased with this refactor! But anyway, regarding the bug
fix which actually motivated this: if I've done my job correctly, this
should solve some crashes, such as these (which were what tipped me off
to this bug in the first place):

https://codeberg.org/ziglang/zig/actions/runs/2306/jobs/7/attempt/1
https://codeberg.org/ziglang/zig/actions/runs/2173/jobs/6/attempt/1

...and, who knows, perhaps even the random SIGSEGVs we've seen on some
targets! Probably not, but one can hope.
2026-03-15 11:47:14 +00:00
Alex Rønne Petersen 05c059e563 link.Lld: pass --be8 to ld.lld for armeb/thumbeb v6+
BE32 is deprecated and only supported by older cores and some v6 cores. All
cores v6 or newer support BE8, so default to that for v6+.

closes https://codeberg.org/ziglang/zig/issues/31404
2026-03-13 14:58:12 +01:00
Antonin Décimo ea9d593455 Mach-O: accept and skip CIE augmentation string 'S' in .eh_frame
```
* thread #1, name = 'zig', stop reason = breakpoint 1.1
    frame #0: 0x00000000028387c3 zig`link.MachO.eh_frame.Cie.parse(cie=0x000000003cd62060, macho_file=0x000000003ca857c0) at eh_frame.zig:56:21
   53                       else => @panic("unexpected lsda encoding"), // TODO error
   54                   }
   55               },
-> 56               else => @panic("unexpected augmentation string"), // TODO error
                            ^
   57           };
   58       }
   59
(lldb) frame variable
(link.MachO.eh_frame.Cie *) cie = 0x000000003cd62060
(link.MachO *) macho_file = 0x000000003ca857c0
([]u8) data = "\x14\x00\x00\x00\x00\x00\x00\x00\x01zRS\x00\x01x\x1e\x01\x10\x0c\x1f\x00\x00\x00\x00"
([]u8) aug = "zRS"
(Io.Reader) reader = {
  vtable = 0x0000000005407ec0
  buffer = "\x01x\x1e\x01\x10\x0c\x1f\x00\x00\x00\x00"
  seek = 5
  end = 11
}
(unsigned char) ch = 'S'
```

zig supports RPL for augmentation strings, and finds zRS (though it
scans RS). It panics on S. Presumably the parser should just ignore
this at this stage. (found [this description][1], and a bit of code [here][2]
and [there][3]).

[1]: https://www.airs.com/blog/archives/460
[2]:
https://github.com/eliben/pyelftools/blob/main/elftools/dwarf/callframe.py#L287
[3]: https://sourceforge.net/p/elftoolchain/tickets/557/

> The character ‘S’ in the augmentation string means that this CIE
> represents a stack frame for the invocation of a signal
> handler. When unwinding the stack, signal stack frames are handled
> slightly differently: the instruction pointer is assumed to be
> before the next instruction to execute rather than after it.

Signed-off-by: Antonin Décimo <antonin.decimo@gmail.com>
2026-03-11 23:21:57 +01:00
Matthew Lugg ea7e34224a compiler: don't call getUnionLayout on packed unions 2026-03-10 10:26:15 +00:00
Matthew Lugg c2b42383eb compiler,std: various little fixes 2026-03-10 10:26:14 +00:00
Matthew Lugg 4eb8360911 compiler: various lil' fixes 2026-03-10 10:26:14 +00:00
Matthew Lugg 51c23f7ba4 compiler: split default field values back out from layout resolution
I was trying out combining struct layout resolution with resolution of
default field values, but it broke a few cases which it's not clear we
want to break. The simplest such case was a struct with a field which
was a slice of itself, with a default value of `&.{}`.

So, at least for now, I'm accepting defeat and splitting this back out.
This allows a couple of behavior tests which were removed to be
re-introduced---I will do that in the commit following this one.

I have *not* made this separate phase of resolution "lazy": instead, it
is tied to layout resolution, in the sense that if a struct's layout is
referenced, then its default field values are also referenced. I chose
this approach for simplicity---not of the implementation (it's actually
slightly *more* code to do it this way!), but in terms of the language
specification. I think this behavior is easier to understand and keep in
your head. It can be easily changed in future if we decide we want to.

This partially reverts the commit titled "compiler: merge struct default
value resolution into layout resolution".
2026-03-10 10:26:13 +00:00
Matthew Lugg 160da8d6a4 Dwarf: be even dumber about source locations 2026-03-10 10:26:13 +00:00
Matthew Lugg 5cc12da1c0 cbe: rework CType and other major refactors
The goal of these changes is to allow the C backend to support the new
lazier type resolution system implemented by the frontend. This required
a full rewrite of the `CType` abstraction, and major changes to the C
backend "linker".

The `DebugConstPool` abstraction introduced in a previous commit turns
out to be useful for the C backend to codegen types. Because this use
case is not debug information but rather general linking (albeit when
targeting an unusual object format), I have renamed the abstraction to
`ConstPool`. With it, the C linker is told when a type's layout becomes
known, and can at that point generate the corresponding C definitions,
rather than deferring this work until `flush`.

The work done in `flush` is now more-or-less *solely* focused on
collecting all of the buffers into a big array for a vectored write.
This does unfortunately involve a non-trivial graph traversal to emit
type definitions in an appropriate order, but it's still quite fast in
practice, and it operates on fairly compact dependency data. We don't
generate the actual type *definitions* in `flush`; that happens during
compilation using `ConstPool` as discussed above. (We do generate the
typedefs for underaligned types in `flush`, but that's a trivial amount
of work in most cases.)

`CType` is now an ephemeral type: it is created only when we render a
type (the logic for which has been pushed into just 2 or 3 functions in
`codegen.c`---most of the backend now operates on unmolested Zig `Type`s
instead). C types are no longer stored in a "pool", although the type
"dependencies" of generated C code (that is, the struct, unions, and
typedefs which the generated code references) are tracked (in some
simple hash sets) and given to the linker so it can codegen the types.
2026-03-10 10:26:12 +00:00
Matthew Lugg b27c56fe50 compiler: get everything building
Several backends are crashing right now. I'll need to fix at least the C
backend before this branch is ready to PR.
2026-03-10 10:26:12 +00:00
Matthew Lugg f7a1ccfc56 compiler: fix up LLVM backend, and improve its debug info
The LLVM backend can now run the behavior tests and standard library
tests, like the x86_64 backend can. This commit required me to make a
lot of changes to how the LLVM backend lowers debug information, and
while I was doing that, I improved a few things:

* `anyerror` is now an enum type (and other error sets just wrap it), so
  error values appear by name in debuggers

* Fixed broken lowering for tagged unions with zero-width payloads

* Associate container types with source locations in all cases

* Avoid depending on the order of type resolution (using the new
  `DebugConstPool` abstraction), so debug information will contain all
  available type information rather than just the subset which happens
  to be resolved when the backend lowers that debug type
2026-03-10 10:26:12 +00:00
Matthew Lugg bcb1a6bdf3 compiler: make Dwarf and self-hosted x86_64 happy
Introduces a small abstraction, `link.DebugConstPool`, to deal with
lowering type/value information into debug info when it may not be known
until type resolution (which in some cases will *never* happen). It is
currently only used by self-hosted DWARF logic, but it will also be of
use to the LLVM backend (which is my next focus).
2026-03-10 10:26:11 +00:00
Matthew Lugg 650185692d compiler: merge struct default value resolution into layout resolution
This actually doesn't cause any dependency loops in std, which is pretty
much my benchmark for it being acceptable. This can be reverted if it
turns out to be problematic, but for now, let's err on the side of
language simplicity.

To be clear, this *does* regress some cases which previously worked: I
will have to remove some behavior tests as a result of this commit. To
be honest, the tests which look to be failing as a result of this are
things which I think are generally unadvisable; I actually reckon a bit
more friction to use default field values in non-trivial ways might be a
good thing to stop people from misusing them as much. Struct fields
should very rarely have default values; about the only common situation
where they make sense is "options" structs.
2026-03-10 10:26:08 +00:00