6l: modernise -H6 (LC_MAIN, PIE, libSystem), mirror of the 7l work#6
Open
rafael2knokia wants to merge 4 commits into
Open
6l: modernise -H6 (LC_MAIN, PIE, libSystem), mirror of the 7l work#6rafael2knokia wants to merge 4 commits into
rafael2knokia wants to merge 4 commits into
Conversation
Modernizes the amd64 Mach-O output of 6l, taking -H6 from an "old Mac OS X" image (LC_UNIXTHREAD, unsigned, static) to a current-macOS one that dyld will actually load: LC_MAIN entry point instead of the UNIXTHREAD register-state entry, MH_DYLDLINK|MH_TWOLEVEL in the header, a libSystem LC_LOAD_DYLIB, and LC_DYLD_INFO_ONLY, LC_BUILD_VERSION, LC_UUID load commands. The amd64 output stays non-PIE here (a follow-up switches 6l to RIP-relative addressing and sets MH_PIE); the change is entirely gated in src/cmd/ld/macho.c by `case '6'`, so 8l and other users of the same file are unaffected. Also raises 6l's default INITTEXT from 4096+HEADR to 0x100000+HEADR: Linux's mmap_min_addr is 64K by default and refuses lower mappings, so a __TEXT at 0x1088 could not be loaded by darling; 1MB clears it while staying < 2GB, which the amd64 32-bit-absolute addressing still needs. (Apple uses a 4GB __PAGEZERO; going that high would need a wider INITTEXT type in 6l's text layout -- separate work.) Mirrors the 7l/arm64 macOS support added in ba7132b ("7a/7l: produce macOS arm64 Mach-O executables (-H6)"). Test: tests/s/mini/hello_macos_amd64.exe rebuilt with `6l -s -H6` loads and runs under darling; ELF (-H7) and Plan 9 (-H2) outputs are byte-identical.
Make the amd64 macho output position-independent, mirroring the arm64 work in ba7132b. A symbol memory reference (LEAQ name(SB), ...) is now encoded RIP-relative ([rip+disp32] via a D_PCREL reloc) instead of an absolute disp32 SIB form, and the Mach-O header sets MH_PIE. The change is gated on HEADTYPE==6, so ELF (-H7) and Plan 9 (-H2) keep the proven absolute encoding (verified: Linux output is byte-identical). - span.c asmandsz(): for HEADTYPE==6, emit mod=00,rm=101 (RIP-relative) and mark the reloc D_PCREL. doasm() then corrects the addend for any immediate emitted after the disp32 (RIP is relative to the end of the whole instruction), via the new riprelfix. - macho.c: OR MH_PIE into the header flags. This is code-only PIE: a program with absolute pointers in __DATA would still need rebase opcodes (not emitted). __PAGEZERO stays 1MB rather than Apple's 4GB because INITTEXT>=4GB hits a separate 32-bit truncation in 6l's text layout (no code emitted); MH_PIE lets the loader slide the image regardless. Verified: macOS entry disassembles to lea rax,[rip+0x3f5] resolving to the real __DATA address; a no-syscall PIE binary (mov eax,42; ret) loads and runs under darling and exits 42 via dyld's LC_MAIN return->exit path.
Add "6l -I got:remote:lib" to declare a Mach-O dynamic import. The program defines a GOT pointer slot `got` (8 bytes) in __DATA and calls through it; the linker emits an LC_DYLD_INFO non-lazy bind opcode stream so dyld resolves `remote` from `lib` (libSystem, ordinal 1) into that slot at load. This lets hand-written Mach-O binaries call libc functions instead of issuing raw Darwin syscalls -- required to run under darling, which emulates Darwin in userspace via libSystem and cannot translate the raw amd64 Darwin syscalls. - src/cmd/ld/macho.c: adddynimp() + binduleb(); build the bind stream in asmbmacho, append it at the end of __LINKEDIT, and point LC_DYLD_INFO_ONLY bind_off/size at it (cflush before the direct write so it doesn't race machowrite's buffer). - src/cmd/6l/obj.c: -I flag -> adddynimp(). - src/cmd/ld/macho.h: prototype. - tests/s/mini/hello_macos_libc_amd64.s: call _write via the GOT slot. Verified: hello_macos_libc_amd64.exe runs under darling and prints "Hello, world". ELF and Plan 9 outputs are unaffected (dynimp entries are only consumed by the '6' arm of asmbmacho). 7l on arm64 has its own path added by aryx in a separate track.
Add the amd64 counterpart to the arm64 section already in docs/notes_macos.txt: what changes 6l -H6 makes (LC_MAIN, MH_PIE, RIP-relative addressing, -I dynamic imports), why (darling refuses non-PIE / static / raw-syscall Mach-Os), and how to verify with `darling shell ./hello_macos_libc_amd64.exe`. Also record the 6l change under 0.4 in changes.txt, referencing the 7l/arm64 work in ba7132b that this mirrors.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rebased subset of #5, per your comment there: keeps only the 6l /
amd64 pieces you said you'd take. The 7l / arm64 changes are dropped
since
ba7132b7e(7a/7l macOS Mach-O) already covers them from acleaner starting point.
What's in here
Four commits on top of current master (
51b21b872), allcase '6'/HEADTYPE==6gated so ELF (-H7) and Plan 9 (-H2) outputs staybyte-identical:
6l: emit modern Mach-O (LC_MAIN + libSystem) for -H6LC_MAINentry (notLC_UNIXTHREAD), header flagsMH_DYLDLINK|MH_TWOLEVEL,LC_LOAD_DYLIB(libSystem),LC_DYLD_INFO_ONLY,LC_BUILD_VERSION,LC_UUID. Raises thedefault
INITTEXTfrom4096+HEADRto0x100000+HEADRso theimage clears Linux
mmap_min_addrand loads under darling.6l: PIE/RIP-relative addressing for macOS Mach-O (-H6)MOV \$sym(SB)is encoded[rip+disp32]with aD_PCRELreloc(mod=00, rm=101) instead of the absolute disp32 SIB form; header
sets
MH_PIE.doasm()corrects the addend for any bytes emittedafter the disp32 (RIP is relative to the end of the whole
instruction).
6l: -I dynamic imports — call libSystem from Mach-O binariesNew
6l -I got:remote:lib: the program defines an 8-byte GOT slotgotin__DATAand calls through it; the linker emits anLC_DYLD_INFOnon-lazy bind so dyld resolvesremote@lib(libSystem, ordinal 1) into that slot at load. Lets hand-written
amd64 binaries call libc functions -- required to run under darling,
which emulates Darwin via libSystem and cannot translate raw amd64
Darwin syscalls.
docs: 6l -H6 modernisation notes + changes.txt entriesAdds an amd64 section to
docs/notes_macos.txtbeside the existingarm64 one, and records the change under
0.4inchanges.txtreferencing your
ba7132b7e.Verification
Ran locally on Linux:
(cd tests/s/mini && mk clean && mk all)builds every existing target.The full 7l/arm64 side (`hello_macos_arm64.exe`, ad-hoc code
signature, ADRP/ADD,
linkers/lk/macho.c) comes from your masteruntouched.
What's not here (versus #5)
Dropped:
LC_MAIN/ ad-hocLC_CODE_SIGNATURE/sha256.c-- yourba7132b7edoes the equivalent vialinkers/lk/macho.c.-Idynimports and `hello_macos_libc_arm64.s` -- would land asa follow-up on your arm64 path.
ADR-- yourba7132b7euses ADRP/ADD, which is theright shape.
README.mdprose changes -- your `57968451b` already covers this.Known limitations still noted in the notes file:
__PAGEZEROis 1 MB, not Apple's 4 GB, because 6l's text layout usesint32 offsets.
MH_PIElets dyld slide the image regardless, sothis is cosmetic.
binaries; the LINKEDIT slack for
codesign(1)is intentionally leftreachable.
Original PR: #5.