100 Commits
Author SHA1 Message Date
Rui Ueyama 331ac66366 Fix CI 2026-10-22 14:06:23 +09:00
Rui UeyamaandClaude Opus 5.5 11fa24033d Keep symbols versioned with .symver preemptible
If an object file defined foo and its alias foo@VER, references to foo
in a shared object were bound locally, although the definition is
exported as foo@VER, so an executable's copy relocation or interposing
definition didn't reach them. Now foo, if not exported itself, shares
foo@VER's dynamic symbol and is as preemptible as foo@VER.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-21 13:18:54 +09:00
Rui UeyamaandClaude Opus 5.5 605749d515 Keep IFUNCs exported from a shared object preemptible
A shared object's references to an IFUNC that it exports were bound
locally with IRELATIVE relocations, so a definition that interposes the
IFUNC didn't reach them. They now get JUMP_SLOT and GLOB_DAT relocations
against the symbol, as with GNU ld and lld.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-20 11:17:49 +09:00
Rui Ueyama 77d78b9a0e Fix CI 2026-10-19 10:54:16 +09:00
Rui Ueyama 72f728c20b Check for read-only copyrel buffers without catching SIGSEGV
The copyrel-relro tests wrote to each buffer and caught SIGSEGV with
setjmp/longjmp to see if it was read-only. They now read(2) from a pipe
into the buffer instead, which fails with EFAULT if the buffer isn't
writable, so the tests no longer need a signal handler.
2026-10-19 09:27:55 +09:00
Rui Ueyama 6b93c0e18e Put .openbsd.randomdata into RELRO
.openbsd.randomdata holds values such as the stack protector's guard,
which the OpenBSD loader fills with random bytes and which are not
supposed to change afterwards. OpenBSD's GNU ld and lld put the section
into PT_GNU_RELRO so that it becomes read-only after relocation, and
mold now does the same. Upstream lld does it only for ELFOSABI_OPENBSD
inputs, but mold already creates PT_OPENBSD_RANDOMIZE by the section
name alone, so it doesn't check the OSABI.
2026-10-19 09:27:55 +09:00
Rui Ueyama c12b4144fd Create .dynamic for static executables that export symbols
A static executable had no .dynamic, so -E, --dynamic-list and the
other options that export symbols were silently ignored. Such an
executable now has .dynamic and .dynsym with the exported symbols, as
the options ask. It still has no .interp and runs as before.

-static -shared output, which also lacked .dynamic, now has one.
2026-10-19 09:27:55 +09:00
Rui Ueyama d04c073d0a Improve man page 2026-10-11 10:02:43 +09:00
Rui Ueyama 246390167b Accept GNU ld's -t, -n and -i
They are GNU ld's short names for --trace, --nmagic and -r.

https://github.com/rui314/mold/pull/1731.
2026-10-11 09:01:06 +09:00
Rui Ueyama 9fde7131a6 Use mold-common's archive reader in the Mach-O linker
macho/archive_file.rs was a copy of common/archive_file.rs without thin
archive support. The shared reader now does what the copy did better:
it trims the space padding of a BSD short member name, which the ELF
linker kept, skips every __.SYMDEF variant, and returns each member's
date, which the Mach-O linker writes to debug stabs. MappedFile::member
makes a member a Mach-O input named "archive(member)".
2026-10-09 21:34:09 +09:00
Rui Ueyama 0dd2e85f78 Merge the ELF and Mach-O integration tests 2026-10-09 21:02:29 +09:00
Rui Ueyama 042b9cf06c Set e_shnum to 0 from SHN_LORESERVE sections up
e_shnum is a 16-bit field, but its values from SHN_LORESERVE (0xff00)
up are reserved. With that many sections or more, e_shnum must be 0
and the real number goes into the first section header's sh_size. We
did that only past 65535 sections.
2026-10-09 19:10:28 +09:00
Rui Ueyama a1eaf5ff76 Print "mold <version> (<commit>)" for ld64.mold -v
Now that the Mach-O linker is part of mold, its banner no longer says
mold-macho, and it carries the commit hash as the ELF linker's does.
The -sdk_imports report names the linker mold-<version>. The tests
tell mold from Apple's ld with a new is_mold helper in common.inc,
which looks for the banner.
2026-10-09 18:37:41 +09:00
Rui Ueyama 96406a27e1 Move the git hash lookup to mold-common
elf/build.rs looked up the commit mold is built from and made the ELF
linker's version string from it. The Mach-O linker needs the hash as
well, so mold-common's build script now looks it up and exports it as
mold_common::GIT_HASH. The ELF linker's version string is unchanged.
2026-10-09 18:36:53 +09:00
Rui Ueyama afd7b70851 Build the Mach-O linker on Windows
The rest of the Mach-O linker's Unix-only code gets Windows versions.
The output is written with seek_write and created without a file mode.
std gives no file IDs on Windows, so input files are told apart by
their canonical paths. LTO is reported as unsupported on Windows, as
it is for the ELF linker.

The Windows CI jobs now build a Mach-O target as well.
2026-10-09 17:06:42 +09:00
Rui Ueyama cfcd7ee129 Use mold-common's strerror in the Mach-O linker
It was a copy of mold-common's, which also builds on Windows.
2026-10-09 17:03:41 +09:00
Rui Ueyama a51db2cb47 Use mold-common's fork and crash cleanup in the Mach-O linker
macho/subprocess.rs was a copy of common/subprocess.rs, except that its
signal handler removed the Mach-O linker's output rather than the ELF
linker's temporary file. The Mach-O linker now registers its output
with mold-common's set_tmpfile, so the shared signal handler removes it,
as do the fatal error path and the panic hook.
2026-10-09 17:03:01 +09:00
Rui Ueyama 4f76492963 Use mold-common's timers in the Mach-O linker
macho/util/perf.rs was a copy of common/perf.rs without its Windows
code. The only real difference was that the Mach-O linker prints the
timers to stderr, as ld64 prints -print_statistics, so Timers::print
now takes the stream to print to.
2026-10-09 17:01:51 +09:00
Rui Ueyama 0d3ec92304 Stop using Unix-only OsStr conversions in the Mach-O linker
std::os::unix::ffi::OsStrExt doesn't exist on Windows. On Unix,
OsStr::as_encoded_bytes returns the same bytes as OsStrExt::as_bytes,
and mold-common's os_str, which the ELF linker uses, converts bytes
back to an OsStr. This is a step toward building the Mach-O linker on
Windows.
2026-10-09 17:00:38 +09:00
Rui Ueyama 8ca12c6442 Fix a Clippy warning 2026-10-09 16:55:07 +09:00
Rui Ueyama 5d7ba5d627 Install ld64.mold
mold acts as the Mach-O linker under that name. This replaces
mold-macho's install.sh, which installed only that symlink.
2026-10-09 16:54:38 +09:00
Rui Ueyama 227af62689 Run the Mach-O CI on mold's packages
The Mach-O shell tests are now the mold package's macho-integration
test. The executable is built with the Mach-O targets alone, and only
the Mach-O crates' unit tests run on the macOS runner.
2026-10-09 16:53:32 +09:00
Rui Ueyama b0302fbcaf Run the Mach-O tests through an ld64.mold symlink
The mold executable now acts as the Mach-O linker only under that name,
so the harness makes a symlink to it in its working directory and
passes that to the scripts as $mold. The tests run as the
macho-integration test of the mold package; they are skipped on hosts
other than macOS.
2026-10-09 16:53:07 +09:00
Rui Ueyama a662cede04 Run the Mach-O linker if invoked as ld64.mold
As in mold 1.x, one executable holds both linkers and chooses one by
the name it is run as: ld64.mold (or ld64) for Mach-O, anything else
for ELF. That's the name clang looks for with -fuse-ld=mold on macOS,
as it looks for ld64.lld with -fuse-ld=lld.

The Mach-O targets get features of their own, macho-arm64 and
macho-x86_64, which are on by default.
2026-10-09 16:52:12 +09:00
Rui Ueyama dba9aa127e Build the Mach-O test harness only on macOS
The harness calls macOS-only APIs such as confstr's
_CS_DARWIN_USER_TEMP_DIR, so the workspace failed to build on Linux.
The scripts drive Apple's toolchain and can't run elsewhere anyway, so
the crate is now empty on other hosts.
2026-10-09 16:50:39 +09:00
Rui Ueyama 5d05ee37c7 Merge https://github.com/rui314/mold-macho
mold-macho is a Mach-O linker for macOS, written in Rust as a port of
mold. Its tree already follows mold's layout (macho/, arch/macho-*,
tests/macho/), so this merge keeps its history and commit hashes as
they are.

Where both trees have a file, this merge keeps mold's. The Mach-O
crates join the workspace, but the mold executable doesn't use them
yet; the following commits wire them in.
2026-10-09 16:50:20 +09:00
Rui UeyamaandClaude Opus 5.5 953ca90b63 Rename the cli's features to macho-arm64 and macho-x86_64
mold's cli has features named arm64 and x86_64 for its ELF targets.
Prefixing ours keeps the names apart once this linker moves into mold.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 16:34:14 +09:00
Rui UeyamaandClaude Opus 5.5 d2e5695302 Update cpp_demangle to 0.5.1
mold uses 0.5.1. Its Symbol::demangle no longer takes options.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 16:30:45 +09:00
Rui UeyamaandClaude Opus 5.5 d8caed2a76 Move the tests to tests/macho
mold keeps its ELF tests in tests/elf. Putting ours in tests/macho
gives the two trees the same layout.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 16:30:20 +09:00
Rui UeyamaandClaude Opus 5.5 83edba7a8d Explain Mach-O's TLS in a new tls.rs
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 16:20:34 +09:00
Rui UeyamaandClaude Opus 5.5 f8dbc1c147 Expand objc.rs's file comment
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 15:33:42 +09:00
Rui Ueyama 9fcf4a97d9 Fix comments
Rewrite comments whose English was ungrammatical or unidiomatic, and
correct comments that no longer matched the code, such as references to
C++-era functions and files, wrong option and field names, and incorrect
instruction listings. Also fix a typo in a RISC-V error message.
2026-10-09 15:19:28 +09:00
Rui UeyamaandClaude Opus 5.5 222a192f0a Pin the macOS version where the tests' outputs depend on it
Four tests assumed the compiler's default deployment target was
older than macOS 27. diagnostic-options and option-check-order link
for macOS 26 objects the compiler now builds for 27, and the linker's
warning that the objects are newer broke their checks for an output
with no warnings; the objects are built for 26 now. missing-argument
and syslibroot look for a -lazy-l (-lazy_library) dylib in otool -L,
which from macOS 27 on, as in a simulator, loads lazily through no
load command; on macOS they link for 26.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 14:55:34 +09:00
Rui UeyamaandClaude Opus 5.5 962911566b Expect macOS 27's dyld to catch a static initializer's exception
macOS 27's dyld calls each initializer inside a handler
(dyld4::LibSystemHelpers::callInitializer) that catches an exception
leaving it and aborts through abort_report_np, with nothing on stderr,
so the test's uncaught exception never reached libc++abi's terminate
message there, whichever linker made the program (ld-prime's aborts the
same way). An abort is what the uncaught exception comes to there; a
second program catches it inside the initializer, which the unwinding
reaches through the same frames on any version.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-09 14:55:34 +09:00
Rui Ueyama 725874568b Remove an unnecessary file 2026-10-09 14:48:22 +09:00
Rui Ueyama 4988b79cb2 Fix the Windows build 2026-10-09 14:08:03 +09:00
Rui Ueyama 4d367e231c Remove unnecessary reborrows and mutable parameters 2026-10-09 13:59:15 +09:00
Rui Ueyama b2ca095547 Remove unnecessary shared reborrows of ctx
Since Rust 2021, a closure captures the place `*ctx` rather than the
variable `ctx`, so a closure that only reads `ctx` gets a shared
reference even if `ctx` is `&mut Context`. Rebinding `ctx` as `&Context`
before a parallel loop is therefore unnecessary. We keep it only where a
`move` closure captures `ctx` by value.
2026-10-09 13:35:02 +09:00
Rui Ueyama bcc453917a Start x86-64 .plt.got entries of ifuncs in non-PIE executables with endbr64
In a position-dependent executable, the address of an ifunc is that of
its .plt.got entry, so an indirect call to the function lands on the
entry. Like a canonical PLT entry, such an entry now starts with
endbr64 so that it works with IBT. This makes x86-64 .plt.got entries
16 bytes long instead of 8.
2026-10-09 12:37:02 +09:00
Rui Ueyama c00226bed7 Fix Clippy warnings
Closes https://github.com/rui314/mold/pull/1727
2026-10-09 12:37:02 +09:00
Rui Ueyama ff6a03bc69 Read ARM64 build attributes for BTI, PAC and GCS
GCC 16 records -mbranch-protection in AArch64 build attributes
(.ARM.attributes) instead of .note.gnu.property, so an output lost the
BTI, PAC and GCS bits even if all its inputs were compiled with the
flag, and -z force-bti warned about every object file. We now read the
aeabi_feature_and_bits subsection and merge it into
GNU_PROPERTY_AARCH64_FEATURE_1_AND.

Fixes https://github.com/rui314/mold/issues/1725
2026-10-09 12:37:02 +09:00
Rui Ueyama 7866fb4799 Start the ARM64 PLT header with bti c regardless of BTI
PLT entries jump to the PLT header with an indirect branch, so the
header needs a landing pad if BTI is enabled. Like the x86-64 PLT
header, which starts with endbr64 whether or not IBT is enabled, we now
always write `bti c` to it. The header runs only when a symbol is
resolved lazily, so the extra instruction doesn't matter. PLT entries
are on the hot path and still get one only if BTI is enabled.
2026-10-09 12:37:02 +09:00
Rui Ueyama 7f6d60fb80 Support -z gcs-report-dynamic
-z gcs-report-dynamic reports shared libraries that lack the GCS bit of
GNU_PROPERTY_AARCH64_FEATURE_1_AND in their .note.gnu.property. As in
GNU ld, it defaults to `none`, and -z gcs=always implies `warning`
independently of -z gcs-report. OpenEmbedded passes
-z gcs-report-dynamic=none when building systemd, whose link probes use
--fatal-warnings, so the unknown-option warning made configure fail.
2026-10-09 12:37:02 +09:00
Rui Ueyama 55c2971772 Add BTI landing pads for range extension thunks
A thunk jumps to its destination with an indirect branch, but the
compiler doesn't start a function that is only called directly with a
landing pad, and SYSVABI64 makes the linker responsible for that case.
If the output is BTI-enabled, we now create a landing pad consisting of
`bti c` and `b <function>` in the first thunk after such a function's
section, and other thunks jump to it instead.

Thunk::fixed_offsets is renamed upper_bound_offsets, and
ThunkLayout::entry_size max_entry_size, because ARM64 thunk entries vary
in size and the first pass only needs upper bounds of the offsets.
batch_size() and branch_distance() now name the PPC targets explicitly.
2026-10-09 12:11:36 +09:00
Rui Ueyama 822b2eb202 Support -z pac-plt
-z pac-plt turns on the PAC bit of the output's
GNU_PROPERTY_AARCH64_FEATURE_1_AND, makes PLT entries authenticate
.got.plt entries with autia1716, and sets DT_AARCH64_PAC_PLT.
2026-10-09 10:50:00 +09:00
Rui Ueyama 358b0ca290 Support -z gcs and -z gcs-report
-z gcs=implicit|never|always controls the GCS bit of the output's
GNU_PROPERTY_AARCH64_FEATURE_1_AND, and -z gcs-report diagnoses input
files lacking it. -z gcs=always implies -z gcs-report=warning.
2026-10-09 10:49:20 +09:00
Rui Ueyama eec9e37a95 Support -z force-bti and -z bti-report
-z force-bti turns on the BTI bit of the output's
GNU_PROPERTY_AARCH64_FEATURE_1_AND, and -z bti-report diagnoses input
files lacking it. As in lld, -z force-bti implies -z bti-report=warning.
CetReportKind is renamed ReportKind because -z bti-report shares it.
2026-10-09 10:49:20 +09:00
Rui Ueyama 5252daa5d8 Emit BTI PLTs on ARM64
If the output is BTI-enabled, the PLT header and the PLT entries that
may be reached by an indirect branch start with `bti c`, which makes
PLT entries 24 bytes long, and DT_AARCH64_BTI_PLT is set. Since the PLT
size now depends on the merged property, we merge .note.gnu.property
before computing section sizes.
2026-10-09 10:49:20 +09:00
Rui Ueyama 353668da81 Replace PLT_SIZE and PLT_HDR_SIZE with Target::plt_entry_offset
PLT_SIZE didn't mean the same thing on all targets. PPC64V1 PLT entries
are 8 or 12 bytes long depending on their indices, and SPARC64 switches
to a different entry format for large PLTs, so plt::entry_offset() had
special cases for them, and their PLT_SIZE was unused or described only
some entries. Each target now computes the offset of a PLT entry by
itself next to the code that writes the entries, and PLT_HDR_SIZE is no
longer needed outside the targets. The function takes the context
because an ARM64 PLT entry needs room for a BTI landing pad if BTI is
enabled.
2026-10-09 10:47:31 +09:00
Rui Ueyama 38b10b4391 Merge GNU_PROPERTY_AARCH64_FEATURE_1_AND
We used to merge only x86 properties in .note.gnu.property, so an ARM64
output lost GNU_PROPERTY_AARCH64_FEATURE_1_AND even if all its inputs
were compiled with -mbranch-protection. We now AND-merge it as GNU ld
and lld do, and merge x86 properties only on x86.
2026-10-09 10:15:15 +09:00
Rui Ueyama 442f2d57a2 Release the old output mapping before remapping it in extend()
extend() maps the grown output file again when the appended data does
not fit in the existing mapping. That happens mainly when the address
space was too tight to map the file with room to grow, yet the new
mapping was created while the old one still existed, so it needed
address space for both. We now release the old mapping first, as the
C++ version did. The data written through it stays in the file because
the mapping is shared.
2026-10-09 10:15:15 +09:00
Rui Ueyama cfa3d7d58a Merge pull request #1726 from ancieg/tests/support-altlinux-objdump-rel-output
Support ALT Linux objdump relocation output in testsuite
2026-10-08 21:49:13 +09:00
Rui UeyamaandClaude Opus 5.5 6a1eabb9b3 Append a table's little-endian fields with util's push16, push32 and push64
chained_fixups.rs had push16, push32 and push64, unwind_info.rs the
same as closures, and dtrace.rs appended its u16 fields by hand and
its u32 and u64 lists in helpers of its own. They are util's push16,
push32 and push64 now, beside its read and write helpers, and
dtrace's list helpers append with them. code_signature's push_be32
and push_be64, the only big-endian ones, stay its own.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:45:50 +09:00
Rui UeyamaandClaude Opus 5.5 50074775e4 Build a -r output's LC_LINKER_OPTION commands with the other load commands
relocatable.rs built its LC_LINKER_OPTION commands itself
(linker_option_command). The load commands are chunks/mod.rs's
create_*_cmd builders, which -r already takes LC_BUILD_VERSION's from;
this one is create_linker_option_cmd there now.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:43:55 +09:00
Rui UeyamaandClaude Opus 5.5 720b2c5776 Let the stub helper chunk choose to write legacy LINKEDIT's entries
Whether the stub helper is legacy LINKEDIT's, without a header and
with entries that enter dyld_stub_binding_helper, depends on the
options, not the target, but x86-64's write_stub_helper made the
choice and called a helper of its own. stub_helper::copy_buf chooses
now, between Target::write_stub_helper and a new
Target::write_legacy_stub_helper, which x86-64 implements with that
helper; no other target has legacy LINKEDIT.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:42:42 +09:00
Rui UeyamaandClaude Opus 5.5 b99464037c Place a symbol at its stub and GOT slot as Symbol::addr finds them
split_info's Places::sym placed a symbol with no section of its own at
its stub as Symbol::addr finds it, but looked the stubs up again, a
lazily loaded dylib's call helper and a delay-init stub before the
plain stub, the other way around from Symbol::addr; got_slot looked
up the GOT and __lazy_load_got slots as Symbol::got_addr does. Both
resolve through Symbol now: stub_entry, the chunk and address of the
stub, call helper, delay-init stub or selector stub that stands in
for a symbol, which addr returns the address of, and got_slot, the
chunk and address of the slot, which got_addr returns the address of.
The orders differ only for a dylib symbol with both a __stubs entry
and one of the others, which a lazily loaded dylib's never has (the
link refuses it) and a delay-init dylib's has only where the linker
makes the stub itself (_dlopen's, _objc_msgSend's for small selector
stubs, an entry point's); there the split info now records the stub
the calls go to.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:41:26 +09:00
Rui UeyamaandClaude Opus 5.5 ed3be5663b Let each chunk list the pointers it rebases and the references it splits
rebase_info::rebase_locations collected every pointer a loader slides,
the output sections', the selector references', the lazy pointers' and
the GOT's, and split_info's Places listed the references of the stubs,
the lazy pointers, the stub helper, the GOT, the thunks, the lazy-load
and delay-init helpers, the selector stubs and references, the
synthesized records and the rewritten method lists. mold's chunks
write their own dynamic relocations (got.rs's and output_section.rs's
write_dynrels and relr_offsets). Here each chunk's module lists its
own: output_section, objc_stubs, lazy_ptrs and got have
rebase_locations, and stubs, lazy_ptrs, stub_helper, got,
output_section (the thunks and the synthesized records), lazy_helpers,
delay_init, objc_stubs and objc_methlist have split_info_entries,
which rebase_locations and split_info::construct call; Places, Place,
Entry and push are the chunks' to use. Both lists are sorted, so
their order is the same. rebase_info's pointer_relocs, which the
fixup chunks use, is output_section's, as mold's
collect_abs_relocations is, and data_blob_fields, data_blob_pointers
and data_blob_binds are input_files.rs's, beside DataBlob.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:38:01 +09:00
Rui UeyamaandClaude Opus 5.5 d980bc4b1e Keep the mergeable record's chunk in chunks/mergeable_record.rs
MergeableRecordSection, the LC_ATOM_INFO chunk of a -make_mergeable
dylib, and its copy_buf were make_mergeable's, the only chunk defined
outside chunks/. The chunk is chunks/mergeable_record.rs's now, as
mold's chunks/mod.rs holds the .gdb_index chunk; make_mergeable still
builds its contents, as mold's gdb_index.rs builds that chunk's.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:37:02 +09:00
Rui UeyamaandClaude Opus 5.5 e2903c0e98 Look a GOT load's helper up in the chunk that holds it
arch/mod.rs's load_helper looked a rewritten GOT load up in the sites
of the lazy-load helpers and then in those of the delay-init helpers.
Each chunk looks its own up now, lazy_helpers::load_helper and
delay_init::load_helper, and the targets ask one and then the other.
LazyUse and DelayUse stay apart: a lazy-load helper also stands in for
calls, which a delay-init helper never does (a delay-init stub does).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:37:02 +09:00
Rui UeyamaandClaude Opus 5.5 ec1030cef0 Give the Objective-C chunks the code that writes and places their data
The tails of __objc_methname and __objc_selrefs - the selector names
and references of the selector stubs, and the method lists' extra
references - were written by output_section's copy_buf, though
objc_stubs holds them. objc_stubs writes them now (write_methnames and
write_selrefs), as objc_methlist writes the lists placed in an output
section. objc.rs's add_relative_method_list, which adds a rewritten
list to __objc_methlist, is objc_methlist's, and add_classref_stand_ins,
which makes the stand-ins for the GOT entries of the classes whose
__objc_classrefs slots stay, is got.rs's.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:36:33 +09:00
Rui UeyamaandClaude Opus 5.5 950f7d012d List an object's local symbols in ObjectFile::populate_symtab, as mold does
The symbol table's object_locals listed the local symbols a final
image keeps of an object, with keep_local_symbol and is_listed_out
deciding which, and relocatable.rs had a twin object_locals listing a
-r output's. mold's ObjectFile lists its own (populate_symtab, which
should_write_to_local_symtab filters), for a final link and -r alike.
ObjectFile::populate_symtab in input_files.rs lists them now for both:
a final image keeps the non-external symbols but the assembler
temporaries and those the -non_global_symbols lists filter out, each
with no flags and its value filled in when the table is written; a -r
output keeps its labels too, demotes the private externals it defines
and hides rather than drops what -x or the lists filter out, each
with its flags and its value. relocatable.rs's Local is LocalSymbol,
beside it; keep_local_symbol is should_write_to_local_symtab, and it
and is_listed_out are in input_files.rs, as is SymtabBlock, which
mold keeps there.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:35:30 +09:00
Rui UeyamaandClaude Opus 5.5 068cb2d807 Let each chunk list the local symbols it synthesizes, as mold does
The symbol table's linker_locals built the local symbols of every
chunk the linker synthesizes: the selector stubs, the lazy-load
helpers and slots, the delay-init stubs and helpers, and the
range-extension thunks' entries. mold's chunks each produce their own
(chunks/mod.rs's populate_symtab calls those of the PLT, the GOT and
the output sections); here chunks::populate_symtab calls those of
objc_stubs, lazy_helpers, lazy_load_got, delay_init (one for each of
its two chunks) and output_section, whose populate_symtab lists the
section's branch islands, as mold's lists its thunks' symbols.
thunks::island_symbols, which names them and which the map lists too,
is output_section's now, of one section. linker_locals still lists
the locals on synthesized data first, then calls the chunks in the
order the table had them.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:35:03 +09:00
Rui UeyamaandClaude Opus 5.5 88c77c502e Put check_weak_imports after report_undef_errors, where the driver runs it
check_weak_imports stood among the duplicate and weak-export checks,
ahead of claim_unresolved_symbols and report_undef_errors, which the
driver runs before it. It follows them and their helpers now, as mold's
passes.rs follows its driver.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:28:43 +09:00
Rui UeyamaandClaude Opus 5.5 f069ff203b Keep the version sets in cmdline.rs and the hook's classes in bundle_hook.rs
The version sets (VersionSet and VERSION_2012_FALL and the like) decide
the defaults the options take for a deployment target, which the
passes ask through Args::targets and predates; they were in macho.rs,
with the file format. They are in cmdline.rs now, beside Args, as
mold's option defaults are. input_files::exported_classes, the classes
a re-exported library exports, which only the hook for the classes of
mergeable libraries asks, is bundle_hook.rs's, with is_class_export;
input_files.rs lends it read_tbd and read_dylib_binary.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:28:43 +09:00
Rui UeyamaandClaude Opus 5.5 156508238e Keep Context's last helpers where mold has them
Context still answered a few questions it has no part in: whether an
object is one LTO compiled (is_lto_obj), whether the link strips dead
code (strips_dead_code), and the image base the layout starts from
(image_base); and it defined BoundarySym, the boundary symbols'
record. mold's ObjectFile says what made it (origin), its driver
checks args.gc_sections itself, and the layout and synthetic symbols
are its passes'. An object made by LTO says so (lto_output, read by
ObjectFile::is_lto_obj), strips_dead_code is dead_strip.rs's, and
image_base, which only the layout asks, and BoundarySym are
passes.rs's, image_base beside mach_header_addr and BoundarySym
beside claim_boundary_symbols.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:28:18 +09:00
Rui UeyamaandClaude Opus 5.5 0d4ec2d7d0 Write out the passes' one-line helpers where they are used
init_function, the -init function if it is defined, check_tlv_template,
the check of thread-local data a rename moved out of the template, and
write_merged_bitcode, which only called lto::write_merged_bitcode, had
one caller each, as mold would have them written out: convert_init_offsets,
set_osec_offsets and the driver have them in place now, their comments
with them. mark_live_objects loaded the members defining the entry
point and -u symbols with a copy of load_owner, which it calls for
them now. check_initializers and its helpers come before
convert_init_offsets, which the driver runs after it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:27:31 +09:00
Rui UeyamaandClaude Opus 5.5 a9a45066e0 Run the dylib checks after dead_strip_dylibs from the driver
dead_strip_dylibs ended with two diagnostics of its own: that an image
bound for the dyld shared cache links only libraries in it
(check_shared_cache_deps), and that a dynamic image loads a dylib at
all (check_libsystem_linked). They read what it leaves but are no part
of stripping, so the driver runs them right after it as passes of their
own, as mold's driver runs checks like check_shlib_undefined. They
follow dead_strip_dylibs in passes.rs too.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:27:31 +09:00
Rui UeyamaandClaude Opus 5.5 87958e9b77 Ask Args what the segment options make of a segment
Three helpers of the layout read the options alone, passed the whole
context: dyld_slides, whether dyld loads the image anywhere it likes;
seg_page_size, a segment's -seg_page_size or the page; and
follows_pinned_segment, whether -segment_order lists a segment after
one -segaddr pins. They are Args methods now, beside segaddr, as mold
keeps what the options decide in its Context's arg. dyld_slides is no
opposite of rebase_info::is_never_slid, which a -static image fails
too, so the two stay apart. is_pin_no_base, which place_segments
alone asked, is written out there.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:27:31 +09:00
Rui UeyamaandClaude Opus 5.5 b6418cfff5 Keep the chunks' layout helpers in their chunk modules
Some helpers of passes.rs were about one chunk: finish_unwind_info
encodes __unwind_info again once every segment is placed, init_func
makes an __init_offsets entry of a symbol, resolve_entry took the
address LC_MAIN and LC_UNIXTHREAD name, and resolve_stub_binder finds
the helper legacy LINKEDIT's stub helper jumps to. They are
unwind_info::finish_unwind_info, InitFunc::new and
stub_helper::resolve_stub_binder, beside ensure_stub_binder, now, and
the entry point's address is chunks/mod.rs's entry_addr, as in mold,
which the load commands ask rather than a Context field that a pass
set after layout. An undefined entry point is still reported by a
pass, check_entry_point, where the driver ran resolve_entry.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:27:31 +09:00
Rui UeyamaandClaude Opus 5.5 309b8cd8df Resolve each object's symbols in ObjectFile methods, as mold does
The passes that resolve symbols looped over each object's symbols
themselves: race_definitions, claim_definitions and claim_locals, and
weak_def_losers and import_references, passed an object's index. mold
has the file resolve its own symbols (ObjectFile::resolve_symbols and
initialize_local_symbols), the passes only running the files in
parallel. The per-object loops are ObjectFile's race_definitions,
claim_definitions and initialize_local_symbols now, and
weak_def_losers and import_references ObjectFile methods; the passes
keep their parallel loops over the objects. claim_locals follows
mark_live_objects, after which resolve_symbols runs it.

The dylibs' side of resolution stays in passes.rs: it ranks the dylibs
of the link as a whole and claims symbols table-wide, from the
objects' ranks of the round, rather than reading a file. dylib_ranks,
which nothing else calls, is private.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:27:31 +09:00
Rui UeyamaandClaude Opus 5.5 33cacc7e81 Rank a subsection's labels in input_sections.rs, beside label
InputSection's label and name choose the symbol that names a
subsection, by input_files.rs's subsec_name_rank among the labels
is_private_label doesn't drop. Both are in input_sections.rs now,
beside msym_label_key, which label also uses; icf.rs, the map file
and the mergeable records take them from there.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:19:57 +09:00
Rui UeyamaandClaude Opus 5.5 4839893703 Ask a dylib for its bind ordinal, and a symbol for an export's
Context's bind_ordinal took a dylib's index and its export_bind_ordinal
read -flat_namespace for an interposable export. The ordinal of an
import is DylibFile's bind_ordinal now, which is passed whether the
image is flat namespace, as sold's DylibFile carries its dylib_idx;
the export's is Symbol's export_bind_ordinal, beside the bind_ordinal
that picks between them. An import left to dynamic lookup has no
dylib, and Symbol::bind_ordinal gives it the flat lookup, as
binds_weak_lookup tells it apart; the symbol table, the export trie
and the chained fixups, which took the ordinal of a symbol's dylib by
its index, ask the symbol for it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:19:57 +09:00
Rui UeyamaandClaude Opus 5.5 867ab0b2e3 Look for a dylib's dependencies in reader.rs
input_files.rs resolved a dylib's re-exported install names to files
(resolve_dylib_ref, find_dylib_ref and find_by_leaf, find_reexport
for the stubs prefetched ahead of the link, and loader_rpath and
dir_of for @loader_path), through reader.rs's Prober and under_root.
sold's input-files.cc has its find_external_lib, but mold looks for
libraries in reader.rs, as find_library; the reexports' search is
there now too, beside find_library and find_framework, and
find_reexport is private to it.

reader::warn_about_sections walked the staged objects to warn of
their sections; it is StagedObject's warn_about_sections now, which
load_pending calls for each object in input order.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:19:57 +09:00
Rui UeyamaandClaude Opus 5.5 3b72e4e657 Find a relocation's section in input_files.rs and read integers in util
The targets' read_relocs took the section a non-extern relocation
points into from arch/mod.rs's section_target. It is input_files.rs's
now, beside the StagedObject code that turns that section and offset
into a subsection, as sold's ObjectFile::find_subsection does both;
read_relocs needs nothing from it but the section headers it already
gets.

arch/mod.rs had the targets' little-endian read32, write32 and write64
and mergeable/mod.rs its own read16, read32 and read64, which took an
offset besides the slice. They are one set in util now, of the form
the targets used, which mold's read_ul32 and the like have too: the
integer at the start of a slice.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:19:57 +09:00
Rui UeyamaandClaude Opus 5.5 bc98b76f3b Keep the internal object's synthetic inputs beside ObjectFile::internal
What the link synthesizes into the internal object was added from
four places: Context's add_synthetic_section and add_data_word,
objc.rs's add_placed_isec and add_data_blob with the DataBlob and
DataField records they make, and delay_init's add_cstring. A data blob
is no Objective-C record alone: bundle_hook's class table, the lazy
loads' flags and __dyld_private are blobs too. mold's internal object
is an ObjectFile that ObjectFile::internal makes, in input_files.rs;
these are functions of input_files.rs beside it now. They add
subsections to the link's arena and blobs to its list, not to the
object alone, so they take the context rather than being the
object's methods. Their callers bind the section header they add to
a local first.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:19:57 +09:00
Rui UeyamaandClaude Opus 5.5 9b9914967b Dissolve output_sections.rs into passes.rs and the chunks, as in mold
mold has no output_sections.rs: the rules that name an input section's
output section and bin it there (output_name, output_section_key,
create_output_sections) are in passes.rs, as are the passes that order
and size the sections, and each chunk's own layout is in its module.
The section naming and assignment rules, the -order_file sorting, the
placement of the synthesized sections, the ordering of the sections
and segments and the checks on them move to passes.rs, as they are,
in the order the driver runs them. append_tail, which gives an output
section its tail, moves to chunks/output_section.rs; data_seg, the
segment the GOT, the lazy pointers and the image info take, to
chunks/mod.rs; trace_symbol_layout to mapfile.rs, beside the map whose
symbols it lists; and common_owners to symbol_moves.rs, its only user.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:18:43 +09:00
Rui UeyamaandClaude Opus 5.5 a64c091d7c Lay out __eh_frame in chunks/eh_frame.rs, as mold's construct
The pass that drops the FDEs of folded functions, gives the CIEs and
FDEs their offsets and sizes __eh_frame, and the warning about FDEs
beyond __unwind_info's reach, were output_sections.rs' lay_out_eh_frame
and warn_eh_frame_too_large. mold builds its .eh_frame in
chunks/eh_frame.rs' construct, beside the code that writes it; the
layout is construct there now, and the warning a helper it calls.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:18:43 +09:00
Rui UeyamaandClaude Opus 5.5 1b9e6ecae9 Split create_output_sections into passes, as mold's driver runs them
mold has no one function that lays the output out: its driver bins the
input sections with create_output_sections, makes the linker's own
sections with create_synthetic_sections, and orders and sizes them with
sort_output_sections and compute_section_sizes, one pass at a time.
output_sections::create_output_sections ran all of that in one
function. It is split into those passes now, and the Mach-O-only steps
between them (sort_section_members, rename_synthetic_sections,
add_boundary_sections, create_segments, the order checks and so on)
into passes of their own, which the driver calls one by one in the
order they ran. The stubs, the GOT and the __LINKEDIT tables are added
by create_synthetic_sections, as mold adds its .got and .plt there and
sold its tables in create_synthetic_chunks. The driver finds the symbol
moves, which the input sections' assignment and the method lists'
layout both follow, and hands them to the two passes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 18:18:43 +09:00
Rui UeyamaandClaude Opus 5.5 1a23ba49c3 Call functions and fields by mold's names
Several functions did what one of mold's does under another name. They
take mold's now: relocatable::link is combine_objects, and its
assign_file_offsets, sort_sections and build_symtab are
set_osec_offsets, sort_output_sections and create_output_symtab, as in
mold's relocatable.rs; output_sections' sort_chunks is
sort_output_sections; thunks' needs_thunk is requires_thunk; icf's
is_candidate and edge_of are is_eligible and edge_target; the symbol
table's write_symtab is its copy_buf; copy_mach_header is
write_mach_header, as mold's write_ehdr; Target::apply_relocs is
apply_reloc_alloc; OutputFile's create and finish are open and close;
the chunks that build their contents (the dyld info streams, function
starts, data in code, split info, the relocations, the mergeable
record) do so in construct; the driver's print_statistics is passes'
show_stats; and an object's is_alive is is_reachable.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:56:27 +09:00
Rui UeyamaandClaude Opus 5.5 fcd1d6aecc Call an input section's contents, visit and kill by mold's names
InputSection read its bytes through data(), set its visited bit with
mark_visited and was marked dead with set_alive(false). mold's
InputSection has contents(), visit() and kill() for these; the
methods are named so here too, and the passes that drop a subsection
call kill(). set_alive stays for dead stripping, which sets the bit
to what its walk found.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:53:10 +09:00
Rui UeyamaandClaude Opus 5.5 26be971d07 Keep the CFI records in input_sections.rs, as mold does
The compact-unwind records and the __eh_frame CIEs and FDEs (Cie and
Fde) were defined in input_files.rs, which parses them. mold keeps
its CieRecord and FdeRecord in input_sections.rs, beside the sections
they describe, and sold its UnwindRecord with Relocation. UnwindRecord,
UNWIND_NONE and the CIE and FDE records are in input_sections.rs now,
the latter named CieRecord and FdeRecord as mold and sold name them,
and StagedObject::parse_eh_frame is parse_ehframe, mold's name for
the function that reads them. input_files.rs still parses them, and
CieRecord reads the DW_EH_PE_sdata4 encoding from there.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:53:10 +09:00
Rui UeyamaandClaude Opus 5.5 c3d7a8986f Name a subsection and report its relocations through the subsection
Context named a subsection in a diagnostic (subsec_label,
subsec_label_index, subsec_name and subsec_ref, with the free
label_key and msym_label_key), reported a relocation it can't apply
(fixup_error, target_has_address) and noted text relocations
(check_text_reloc, note_text_reloc), each passed the subsection's
index. mold's InputSection names itself (display, func_symbol) and
reports its own relocations (check_range, report_out_of_range,
record_undef_error). They are InputSection's label, label_index,
name, location, fixup_error, target_has_address and check_text_reloc
now, label_key a method of its own and msym_label_key beside it in
input_sections.rs. check_text_reloc still takes the subsection's
index, which the text relocations it notes are recorded by. The
targets' helpers that report a fixup error take the subsection rather
than its index.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:53:10 +09:00
Rui UeyamaandClaude Opus 5.5 9622c65259 Ask a relocation for its target, as sold does
A relocation's target - its symbol, the subsection it lives in, whether
it is thread-local data, its address and its name in a diagnostic -
came from Context (reloc_target_sym, reloc_target_isec,
reloc_target_is_tls, reloc_target_addr and reloc_target_name), passed
the index of the object the relocation is of. sold asks the relocation
(Relocation::sym, subsec, refers_to_tls and get_addr); here they are
Reloc::sym, subsec, refers_to_tls and addr, and target_name, passed the
object itself, as mold's InputSection::rels is, since a Reloc names its
symbol by its index in the object's symbol list. The callers that
looked a relocation's target up in a loop take the object once, the
DTrace site helpers of the targets included, and thunks.rs, which
sliced a subsection's relocations by hand, and the two places that
looked a header up by hand ask the subsection too.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:52:49 +09:00
Rui UeyamaandClaude Opus 5.5 be61fa4668 Ask an input section for its address, header and relocations
A subsection's output address, section ordinal, parent header and
relocations came from Context (isec_addr, isec_sect_idx, hdr_of,
isec_relocs) or, for callers holding a borrow of ctx.isecs, from
input_files::isec_relocs_of, and literal-merge redirects were followed
by Context::resolve_isec. mold asks the section itself:
InputSection::addr(ctx), InputSection::rels(file) and
InputSection::sh_type(file), the header coming through the object's
section list. They are InputSection::addr, sect_idx, hdr(file) and
rels(file) now, isec_relocs_of going with isec_relocs, and the
redirects are followed by the arena, InputSections::resolve, as sold
follows a subsection's replacer.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:51:25 +09:00
Rui UeyamaandClaude Opus 5.5 06b458f1bb Name the symbol flag setters and the name lookup as mold does
Symbol's flag setters repeated their getters' is_ (set_is_imported
for is_imported); mold pairs is_imported with set_imported, and so do
all of sym_flag!'s setters now (set_extern, set_weak_def,
set_private_extern and the rest; set_no_dead_strip already was).
SymbolTable::get, which looks a name up without interning it, is
lookup, mold's name for it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:48:37 +09:00
Rui UeyamaandClaude Opus 5.5 1107fc340e Make the symbol addresses Symbol methods, as mold has them
A symbol's address, its GOT slot's, its stub's, the pointer its stub
jumps through and where a branch to it goes were Context methods
taking the symbol's id (sym_addr, sym_got_addr, sym_stub_addr,
stub_ptr_addr, branch_target_addr). mold's are Symbol methods taking
the context: addr, got_addr, plt_addr and gotplt_addr. These are now
Symbol::addr, got_addr, stub_addr (mold's plt_addr, keeping the
Mach-O name of the section), stub_ptr_addr (its gotplt_addr) and
branch_target_addr. objc_msgsend_got_addr stays on Context, as it
names no symbol.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:48:37 +09:00
Rui UeyamaandClaude Opus 5.5 ce2f56bec8 Make the symbol predicates Symbol methods, as mold has them
What dyld does with a symbol - whether it is an import of a lazy or
delay-init dylib, a TLV descriptor, a weak definition dyld may
coalesce, an interposable export, whether dyld binds its slots and
pointers, by what ordinal, and whether a GOT load of it relaxes - was
asked of Context with the symbol's id. mold asks the symbol, with the
context: Symbol::is_local(ctx), is_pcrel_linktime_const(ctx) and the
like. These are Symbol methods taking the context now;
is_absolute_symbol is is_absolute, mold's name, sym_bind_ordinal is
bind_ordinal, and is_dtrace_pointer_target, which looks at the symbol
alone, takes no context. Where a caller has the symbol at hand, it
asks it directly, and the scans over the whole table iterate the
symbols.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:48:37 +09:00
Rui UeyamaandClaude Opus 5.5 a3f8b6275b Keep the symbols' aux table in SymbolTable, as mold does
The synthetic-slot side table was a Vec on Context, read through
Context::sym_aux, which handed back a shared all-absent record
(NONE_AUX) for the symbols without an entry, and written through
sym_aux_mut, or sym_aux_mut_in where another part of the context was
borrowed at the same time. mold keeps the table in its SymbolTable:
Symbol::aux(&symbols) returns the symbol's record if it has one, and
SymbolTable::aux_mut allocates it on first use; the getters got_idx,
plt_idx and the like return the indices as Options, has_plt and
has_got say whether they are there, and thunk_addr is a method of
Symbol. The table and its accessors are now those, the record is
SymbolAux, mold's name, and its stub_idx getter is mold's plt_idx;
writing the thunk addresses no longer needs the split borrow.

Where the code reads an index the symbol must have - the GOT slot of
a GOT load, the stub the lazy-load helpers call - it unwraps it, as
mold's got_addr and plt_addr do, where it took NO_IDX for one before.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:48:37 +09:00
Rui UeyamaandClaude Opus 5.5 426d6dff8f Refuse a legacy-LINKEDIT dylib bound for the shared cache
An x86-64 dylib for macOS before 10.6 fixes itself up through legacy
LINKEDIT, which the shared cache's builder doesn't read, so ld-prime
refuses one that -add_split_seg_info or its install name makes cache
eligible ("Shared cache eligible dylibs must use bind opcodes or
chained fixups"). mold-macho went on and crashed writing its split
info, which indexed the stub helper's __dyld_private, a word legacy
LINKEDIT doesn't have. It now refuses the dylib as ld-prime does.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:29:46 +09:00
Rui UeyamaandClaude Opus 5.5 dd5bc4bd3c Drop Context's forwards to the stub chunks' sizes
The objc stubs' entry size and the stub helper's header size moved to
their chunks while the sizing code still called them through Context;
now that the sizing is in the chunks too, the forwards go.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:26:56 +09:00
Rui UeyamaandClaude Opus 5.5 5eb4fb99d7 Write the output from the driver, as mold does
passes.rs's copy_chunks copied the chunks and then wrote the rest of
the output itself: it reported the text relocations, wrote the fixups,
applied the target's optimization hints, wrote the symbol table, the
mach header, the UUID and the code signature, and queued each range of
the buffer to the output file as soon as it was final. In mold,
copy_chunks is in driver.rs and only copies, and the driver calls the
passes after it one by one (finish_output, rewrite_endbr,
write_build_id). copy_chunks is in driver.rs now and copies only, and
the driver runs the rest in the same order: report_text_relocs and
compute_uuid are pub passes of passes.rs, and the fixups, the symbol
table, the header and the signature are written by the chunk modules
as before. The driver queues each range at the same point as
copy_chunks did, so the file is still written while the rest of it is
produced.

compute_uuid keeps its name. It is mold's write_build_id, as its doc
comment now says, but everywhere else the Mach-O build ID is the UUID
(LC_UUID, -no_uuid, ctx.uuid), and the name says what it computes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:26:55 +09:00
Rui UeyamaandClaude Opus 5.5 a0ea339f6d Give the __LINKEDIT tables their alignment where their headers are made
The layout looked a __LINKEDIT table's alignment up in a table of its
own in passes.rs (chunk_p2align), each table's header saying 0. sold
sets each chunk's p2align in its constructor, the __LINKEDIT tables'
too, and its layout aligns each chunk to its header's. The tables' new
functions now set the alignment ld-prime gives them - 8 bytes for the
symbol and string tables, the export trie, the function starts, the
data-in-code entries, the split info, the mergeable record and the
external relocations, 4 for the indirect symbol table and 16 for the
code signature - and layout_segment reads the header's, as it does a
section's. The others keep the 0 of ChunkHeader::linkedit, which says
why ld-prime does not align them.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:26:54 +09:00
Rui UeyamaandClaude Opus 5.5 689d15b263 Encode the unwind info, chain starts and relocations in their chunks
The layout in passes.rs encoded __unwind_info (encode_unwind_info),
found the chains __chain_starts lists (finish_chain_starts) and stored
the local and external relocations with the tables' sizes
(collect_relocations). As sold's chunks size and fill themselves in
their compute_size, chunks/unwind_info.rs encodes the section in its
compute_size, which layout_segment and finish_unwind_info call (the
name encode_unwind_info being the encoder's there),
chunks/chain_starts.rs finishes its starts, and the local_relocs and
extern_relocs builders store their records and size their tables,
called from build_linkedit_tables as the mergeable record's is.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:26:53 +09:00
Rui UeyamaandClaude Opus 5.5 a33b979f3b Lay out an output section's members in its module, as mold does
compute_section_sizes in output_sections.rs laid out each output
section's members itself. mold's compute_section_sizes calls
chunks/output_section.rs's layout for each section in parallel and
records the sizes; the per-section layout is now
chunks::output_section::layout here too. It returns the members'
offsets rather than writing them, as an InputSection's offset is no
atomic here, and compute_section_sizes still records them serially.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:26:53 +09:00
Rui UeyamaandClaude Opus 5.5 a45881b068 Lay out the method lists and merge the image info in their chunks
output_sections.rs laid out __objc_methlist (lay_out_objc_method_lists)
and merged the objects' __objc_imageinfo records
(merge_objc_image_info), with merge_objc_info and objc_image_flags from
passes.rs. They are in chunks/objc_methlist.rs and
chunks/objc_imageinfo.rs now, the latter as create, after sold's
ObjcImageInfoSection::create, which makes the section from the
objects' records; passes.rs's check_objc_flags, which reports the
records that disagree, calls merge_objc_info there. The two flags they
test are in macho_consts.rs with the other Mach-O constants.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:26:52 +09:00
Rui UeyamaandClaude Opus 5.5 acf30c10ef Size the stubs and the GOT in their own modules, as mold's update_shdr
add_stub_and_got_chunks sized the stubs, the stub helper, the lazy and
lazy-load pointers, the delay-init and lazy-load helpers and the GOT
itself, and create_output_sections and add_objc_stubs the
__init_offsets and __objc_stubs sections. In mold each chunk sizes
itself in its module's update_shdr (plt.rs's, got.rs's), as sold's
chunks do in compute_size. Each of these modules has an update_shdr
now, called where the sizing was; output_sections.rs still decides
which of them the output has. The GOT's places the stand-ins for the
__objc_classrefs slots that stay, which are the GOT's entries, and the
delay-init module has one for each of its two sections.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:26:51 +09:00
Rui UeyamaandClaude Opus 5.5 2906fdd808 Read the API list in cmdline.rs and the $ld$ names in tapi.rs
-sdk_imports_api_list's ApiList and read_api_list were in mapfile.rs,
which writes the report the list limits, though the list is read as
the option is, its one caller in cmdline.rs. They are cmdline.rs's
now, as the other files an option names are read there.

The "$ld$..." directives of a library - LdSymbols, which reads them
for the link's target, with $ld$previous's PreviousDirective and
directive_version, interpret_ld_symbols, which applies them to a
stub's library, and the LdDirectives and MovedExport it leaves - were
in input_files.rs. As in sold, whose tapi.cc has interpret_ld_symbols,
they are tapi.rs's now. A dylib binary's directives are applied in
input_files.rs still, by interpret_binary_ld_symbols with the same
LdSymbols, since the binary is read there.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:16:04 +09:00
Rui UeyamaandClaude Opus 5.5 f486892e5e Share the LEB128 helpers and CityHash through util
The export trie had uleb_len and write_uleb_at of its own and
input_files.rs a read_uleb_at, next to util's encode_uleb and
encode_sleb. util/mod.rs has them now, as mold's common/util.rs keeps
its LEB128 helpers together: read_uleb, mold's, which reads from a
slice it advances (the optimization hints and the CIE and FDE
augmentation data read so), and write_uleb and uleb_size, as sold's
common.h names them (mold's overwrite_uleb rewrites an encoding in
place at its old length, which the trie's zeroed buffer has none of).
A test checks that they agree with encode_uleb. dwarf.rs's Reader
keeps its own uleb and sleb, which return None for a number cut short
by its section's end, where the shared one panics: the reader skips
debug info it can't read.

make_mergeable's CityHash, libc++'s std::hash of a string, is
util::cityhash, next to util::siphash.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:16:04 +09:00
Rui UeyamaandClaude Opus 5.5 4dba60f59b Keep thunks in thunks.rs and ask SymAux about stubs and thunks
The Thunk struct was defined in chunks/output_section.rs, which also
wrote the thunks into the section, while thunks.rs creates them. As in
mold, whose thunks.rs has Thunk and the copy_buf that writes one,
thunks.rs has both now; output_section::copy_buf calls
thunks::copy_buf for the section's thunks.

The search for a thunk entry a branch reaches, thunks::
reachable_thunk_addr, is SymAux::thunk_addr, as mold's
Symbol::thunk_addr looks through the symbol's thunk_addrs. And the
x86-64 target's test of whether an import has no stub of any kind -
neither a __stubs entry nor a lazy-load call helper nor a delay-init
stub - is SymAux::has_stub, mold's Symbol::has_plt. sym_addr and split
info take each kind's address in turn, so they keep testing the
indices one by one.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:16:04 +09:00
Rui UeyamaandClaude Opus 5.5 7faba83f6d Make the relocation, unwind and Objective-C helpers their types' methods
Some questions about one value were free functions in the module of a
chunk that asks them, though other modules ask them too:
rebase_info::is_pointer_reloc, whether a relocation writes a pointer,
which the bind, weak-bind and chained-fixup builders and the external
relocations use as well; unwind_info's function_personality and
function_lsda, an unwind record's personality and LSDA found through
its FDE in DWARF mode, which ICF hashes; eh_frame::lsda_pos, where an
FDE's LSDA pointer is, which ICF, split info and mergeable records
read; and objc::objc_ref_addr, where an ObjcRef points.

As mold's Target::is_absrel says whether a relocation is a word-size
absolute one, is_pointer_reloc is Target::is_absrel, a provided method
taking the Reloc. function_personality and function_lsda are
UnwindRecord's methods next to personality() and lsda(), lsda_pos is
Fde's, and objc_ref_addr is ObjcRef::addr next to ObjcRef::import.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 17:16:04 +09:00