* The `@bitCast` workaround is removed in favor of `@ptrCast` properly
doing element casting for slice element types. This required an
enhancement both to stage1 and stage2.
* stage1 incorrectly accepts `.{}` instead of `{}`. stage2 code that
abused this is fixed.
* Make some parameters comptime to support functions in switch
expressions (as opposed to making them function pointers).
* Avoid relying on local temporaries being mutable.
* Workarounds for when stage1 and stage2 disagree on function pointer
types.
* Workaround recursive formatting bug with a `@panic("TODO")`.
* Remove unreachable `else` prongs for some inferred error sets.
All in effort towards #89.
DWARF 5 moves around some fields and adds a few new ones that can't be
parsed or ignored by our current DWARF 4 parser. This isn't a complete
implementation of DWARF 5, but this is enough to make stack traces
mostly work. Line numbers from C++ don't show up, but I know the info
is there. I think the answer is to iterate through .debug_line_str in
getLineNumberInfo, but I didn't want to fall into an even deeper rabbit
hole tonight.
Handle `__DATA,.rustc` section containing `rustc` metadata - this
is required to get crates like `serde_derive` link properly.
Note to self: this special section has to be copied __verbatim__
from the relocatable object file - this includes preserving its size
even though unpadded according the section's required alignment.
Because ArrayList.initCapacity uses 'precise' capacity allocation, this should save memory on average, and definitely will save memory in cases where ArrayList is used where a regular allocated slice could have also be used.
If these functions are called more than once, then the array list would no longer be guaranteed to have enough capacity during the appendAssumeCapacity calls. With ensureUnusedCapacity, they will always be guaranteed to have enough capacity regardless of how many times the function is called.
Each element of the output JSON has the VM address of the generated
binary nondecreasing (some elements might occupy the same VM address
for example the atom and the relocation might coincide in the address
space).
The generated JSON can be inspected manually or via a preview tool
`zig-snapshots` that I am currently working on and will allow the user
to inspect interactively the state of the linker together with the
positioning of sections, symbols, atoms and relocations within each
snapshot state, and in the future, between snapshots too. This should
allow for quicker debugging of the linker which is nontrivial when
run in the incremental mode.
Note that the state will only be dumped if the compiler is built with
`-Dlink-snapshot` flag on, and then the compiler is passed `--debug-link-snapshot`
flag upon compiling a source/project.
* apply late symbol resolution for globals - instead of resolving
the exact location of a symbol in locals, globals or undefs,
we postpone the exact resolution until we have a full picture
for relocation resolution.
* fixup stubs to defined symbols - this is currently a hack rather
than a final solution. I'll need to work out the details to make
it more approachable. Currently, we preemptively create a stub
for a lazy bound global and fix up stub offsets in stub helper
routine if the global turns out to be undefined only. This is quite
wasteful in terms of space as we create stub, stub helper and lazy ptr
atoms but don't use them for defined globals.
* change log scope to .link for macho.
* remove redundant code paths from Object and Atom.
* drastically simplify the contents of Relocation struct (i.e., it is
now a simple superset of macho.relocation_info), clean up relocation
parsing and resolution logic.
* In watch mode, when changing the C source, we will trigger complete
relinking of objects, dylibs and archives (atoms coming from the
incremental updates stay put however). This means, we need to undo
metadata populated when linking in objects, archives and dylibs.
* Remove unused splitting section into atoms bit. This optimisation
will probably be best rewritten from scratch once self-hosted
matures so parking the idea for now. Also, for easier management
of atoms spawned from the Object file, keep the atoms subgraph as
part of the Object file struct.
* Remove obsolete ref to static initializers in object struct.
* Implement handling of global symbol collision in updateDeclExports.
This is particularly relevant for x86_64 and C++ when relocating
StaticInit sections containing static initializers machine code.
Then, in case of SIGNED_X relocations, it is necessary to have the
full image of the VM address layout of the sections in the object
file as this is how the addend needs to be adjusted for non-extern
relocations.
Also, calculate non-extern, section offset based addends for SIGNED
and UNSIGNED relocations on x86_64 upfront as an offset wrt to the
target symbol representing position of the section/atom within the
final artifact.
Instead of checking for stage1 at every callsite, move the logic
inside `allocateAtom`. This is fine since this logic will disappear
anyhow once I add expanding and shifting segments and sections.
This commit makes it possible to combine self-hosted with a pre-compiled
C object file, e.g.:
```
zig-out/bin/zig build-exe hello.zig add.o
```
where `add.o` is a pre-compiled C object file.
instead, immediately transfer ownership to MachO struct. Also, revert
back to try-ok-fail parsing approach of objects, archives, and dylibs.
It seems easier to try and fail than check if the file *is* of a
certain type given that a dylib may be a stub and parsing yaml
twice in a row seems very wasteful.
Hint for the future: if we optimise yaml/TAPI parsing, this approach
may be rethought!
instead, pass it in functions that require it. Also, when parsing
relocs, make Object part of the context struct where we pass in
additional goodies such as `*MachO` or `*Allocator`.
then, when sorting sections within segments, clear and redo the
ordinals since we re-apply them to symbols anyway. It is vital
to have the ordinals consistent with parsing and resolving relocs
however.
Previously, we'd filter the nlists assuming they were correctly
ordered by type: local < extern defined < undefined within the
object's symbol table but this doesn't seem to be guaranteed,
therefore, we sort by type and address in one go, and filter
defined from undefined afterwards.
For the time being, until we rewrite how atoms are handled across
linkers, store two tables in the MachO linker: one for TextBlocks
directly created and managed by the linker, and one for TextBlocks
that were spawned by Module.Decl. This allows for correct memory
clean up after linking is done.
It makes sense to have them as a dependent type since they only ever
deal with TextBlocks. Simplify Relocations to rely on symbol indices
and symbol resolver rather than pointers.