/*-*- mode: ld-script; indent-tabs-mode: nil; tab-width: 2; coding: utf-8 -*-│ │vi: set et sts=2 tw=2 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2020 Justine Alexandra Roberts Tunney │ │ │ │ This program is free software; you can redistribute it and/or modify │ │ it under the terms of the GNU General Public License as published by │ │ the Free Software Foundation; version 2 of the License. │ │ │ │ This program is distributed in the hope that it will be useful, but │ │ WITHOUT ANY WARRANTY; without even the implied warranty of │ │ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ │ General Public License for more details. │ │ │ │ You should have received a copy of the GNU General Public License │ │ along with this program; if not, write to the Free Software │ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╠──────────────────────────────────────────────────────────────────────────────╣ │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │░░░░░░░█▀█░█▀█░▀█▀░█░█░█▀█░█░░░█░░░█░█░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │░░░░░░░█▀█░█░▄░░█░░█░█░█▀█░█░░░█░░░▀█▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │░░░░░░░▀░▀░▀▀▀░░▀░░▀▀▀░▀░▀░▀▀▀░▀▀▀░░▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │░░░░░░░█▀█░█▀█░█▀█░▀█▀░█▀█░█▀█░█░░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │░░░░░░░█▀▀░█ █░██▀░░█░░█▀█░█▀█░█░░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │░░░░░░░▀░░░▀▀▀░▀░▀░░▀░░▀░▀░▀▀▀░▀▀▀░▀▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│ │░░░░░░░█▀▀░█░█░█▀▀░█▀█░█░█░▀█▀░█▀█░█▀█░█░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░▄▄░░░▐█░░│ │░░░░░░░█▀▀░▄▀▄░█▀▀░█░▄░█░█░░█░░█▀█░█▀█░█░░█▀▀░░░░░░░░░░░░▄▄▄░░░▄██▄░░█▀░░░█░▄░│ │░░░░░░░▀▀▀░▀░▀░▀▀▀░▀▀▀░▀▀▀░░▀░░▀░▀░▀▀▀░▀▀░▀▀▀░░░░░░░░░░▄██▀█▌░██▄▄░░▐█▀▄░▐█▀░░│ │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▐█▀▀▌░░░▄▀▌░▌░█░▌░░▌░▌░░│ ╠──────────────────────────────────────────────────────▌▀▄─▐──▀▄─▐▄─▐▄▐▄─▐▄─▐▄─│ │ αcτµαlly pδrταblε εxεcµταblε § linker │ ╚──────────────────────────────────────────────────────────────────────────────╝ Having an executable run natively on stock Windows / Mac / Linux / BSD entails two steps: (1) create a .com.dbg binary w/ Linux toolchain and then (2) unwrap the .com binary embedded within: objcopy -SO binary input.com.dbg output.com Both executables will work fine, but only the .com format is portable. ───BUILDING───────────────────────────────────────────────────────────── LC_ALL=C ld -T ape/ape.lds ... ───RUNNING────────────────────────────────────────────────────────────── ./foo.com.dbg # works on host machine ./foo.com # works on any os / arch qemu-system-x86_64 -s foo.com # works on any os / arch ───BACKGROUND─────────────────────────────────────────────────────────── The purpose of this software is to help native programs have the same level of consistency, in terms of user experience, that we enjoy with web applications. It's basically like MeteorJS, except primarily CLI, bootable, and more on the order of a few kilobytes than hundred megs. Rather than Isomorphic JavaScript it's built using Isomorphic Binary, since it grants the fastest possible performance and can be trivially emulated in the browser. System resource utilization is also a few kb and GUIs are possible too since Cosmopolitan exports the Windows API, but we recommend doing it with a CLI web server instead and embedding files in your αcτµαlly pδrταblε εxεcµταblε as it's isomorphic to zip. Isomorphic Binary principles state that most platform differences are just numbers, which we integrate easily into a unified business logic through the use of a sufficiently powerful linker. System numbers are otherwise known as ABIs and they're usually the most stable canonical interfaces that platforms provide. This is how we are able to support more versions of Linux than most Linux-only software, e.g. glibc FTMP ───DEBUGGING──────────────────────────────────────────────────────────── Can be done in a few ways: gdb --tui foo.com.dbg gdb --tui foo.com -ex 'add-symbol-file foo.com.dbg 0x200000' gdb --tui -ex 'add-symbol-file foo.com.dbg 0x7c00' \ -ex 'add-symbol-file foo.com.dbg 0x200000' \ -ex -target remote localhost:1234' ───TRANSPARENCY───────────────────────────────────────────────────────── αcτµαlly pδrταblε εxεcµταblε is designed to facilitate maximum transparency to engender trust in this linker process. The headers and symbols can be viewed using readelf or objdump: readelf -Wa input.com.dbg # maximum transparency objdump -wxd input.com.dbg # maximum transparency The disassembly can be viewed using objdump: readelf -Wa input.com.dbg # maximum transparency objdump -d input.com.dbg # maximum transparency objdump -dj.text input.com.dbg # skip αpε boilerplate objdump -j.load -dMi8086 input.com.dbg # fixes real mode code Some commands for controlling the verbosity of binaries: strip -X input.com.dbg # remove ".L" symbols strip input.com.dbg # remove all symbols strip -S input.com.dbg # remove debug info only make CPPFLAGS=-DNDEBUG # remove asserts (prod) make CPPFLAGS=-DIM_FEELING_NAUGHTY # remove legal notices The Makefile build is also configured to always produce a .map file when building each program, which provides further details. ───HACKABILITY────────────────────────────────────────────────────────── Your linker and assemblies were designed provide extensibility through the use of link-time data structures we call "decentralized sections". They allow functions like _init() to be comprised of many small pieces defined throughout the codebase. The same applies to ELF / PE headers. Extending that content usually entails writing a .S file. The process has more in common with JavaScript programming than contemporary C++ development practices. It's the reason Cosmopolitan is able to build the fast tiny multiplatform autonomous binaries that indie developers love using a scalable development model that big businesses respect. ───SECURITY───────────────────────────────────────────────────────────── αcτµαlly pδrταblε εxεcµταblε is designed to be secure in untrustworthy computing environments. Code and data are separated. Data structures initialized at startup are automatically memory protected afterwards. Code intended for platforms you don't use is automatically unmapped too, minimizing any possible chance of impacting your system, while still being there in case you ever need it. ───CONFIDENTIALITY────────────────────────────────────────────────────── αcτµαlly pδrταblε εxεcµταblε is also designed to not leak confidential information by default. Details relating to the host build environment such as system/library versions, user ids, home folder locations, etc. are not taken into consideration at build time since it's hermetic. We can't make speak for debug information, which is why it's put in other files. We also provide the bing and fold programs for auditing binary. ───DESIGN─DETAILS─────────────────────────────────────────────────────── αcτµαlly pδrταblε εxεcµταblε is a non-reflective (a.k.a. flat) binary format that includes ELF, PE, and Macho-O headers only to respect the initialization rituals that supported platforms require. Binaries are sparse because Intel's six thousand page manual says: “Always put code and data on separate pages. [...] If code is to be modified, try to do it all at once and make sure the code that performs the modifications and the code being modified are on separate 4KByte pages or on separate aligned 1-KByte subpages. [...] If (hopefully read-only) data must occur on the same page as code, avoid placing it immediately after an indirect jump [...] or inserting an illegal opcode [...] after the indirect branch [which] may degrade perf in some circumstances.” ──Intel V.O §3.6.9 Support for linking dynamic shared objects is only implemented on Windows NT for the reasons described by Ulrich Drepper in his DSO tutorial. We've implemented this independently of the ld codebase because authentic GNU tooling is powerful enough to generalize to arbitrary formats without needing to add features to its codebase. Cosmopolitan core library functions may be converted to the COFF or Mach-O object formats using objconv. That gives you some freedom to choose to use the Microsoft or Apple linker instead of this one. We otherwise can't use those formats, due to how they heavily restrict naming, which basically makes everything we're doing impossible. In the future an authentic GNU toolchain will be made available on the Windows and Apple platforms, using canonical formats and behaviors. Until then, we can build for those platforms using Linux or WSL. */ #ifdef __LINKER__ #include "ape/macros.h" #include "ape/config.h" #include "libc/nt/pedef.h" #include "libc/zip.h" ENTRY(_start) /* Plans real memory solution at linktime. */ MEMORY { PageZero : org = 0x0000000000000000, len = 0x0000000000001000 RealBss : org = XLM_BASE_REAL, len = XLM_SIZE RealProgram : org = IMAGE_BASE_REAL, len = 0x0000000000010000 - IMAGE_BASE_REAL RealScratch : org = REAL_SCRATCH_AREA, len = REAL_STACK_FRAME - REAL_SCRATCH_AREA RealStack : org = REAL_STACK_FRAME, len = 0x0000000000010000 EbdaMemory : org = 0x0000000000080000, len = 0x0000000000020000 VideoMemory : org = 0x00000000000a0000, len = 0x0000000000020000 Romz : org = 0x00000000000c0000, len = 0x0000000000030000 BiosMemory : org = 0x00000000000f0000, len = 0x0000000000010000 SmallCode : org = IMAGE_BASE_PHYSICAL, len = 0x0000000040000000 - IMAGE_BASE_PHYSICAL ZipData : org = 0x0000000040000000, len = 0x0000000040000000 } PHDRS { Head PT_LOAD FLAGS(5); Rom PT_LOAD FLAGS(5); Ram PT_LOAD FLAGS(6); stack PT_GNU_STACK FLAGS(6); } SECTIONS { /*BEGIN: realmode addressability guarantee */ /*BEGIN: xnu addressability guarantee */ /*BEGIN: linux addressability guarantee */ /*BEGIN: bsd addressability guarantee */ .head SEGMENT_START("text-segment", IMAGE_BASE_VIRTUAL) : { HIDDEN(_base = .); /* Real Mode */ KEEP(*(.head)) . += 1; /* Executable & Linkable Format */ . = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 1); KEEP(*(.elf.phdrs)) HIDDEN(.Lape.phdrs.end = .); . += 1; /* OpenBSD */ . = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 1); HIDDEN(.Lape.note = .); KEEP(*(.note.openbsd.ident)) HIDDEN(.Lape.note.end = .); . += 1; /* Portable Executable */ KEEP(*(.pe.header)) HIDDEN(.Lape.pe.sections = .); KEEP(*(.pe.sections)) HIDDEN(.Lape.pe.sections_end = .); . += 1; /* Mach-O */ KEEP(*(.macho)) . = ALIGN(__SIZEOF_POINTER__); HIDDEN(.Lape.macho.end = .); . += 1; KEEP(*(.ape.pad.head)) . = ALIGN(4096); /* alignments only mandatory when impossible otherwise */ HIDDEN(_ehead = .); } AT>SmallCode :Head /*BEGIN: nt addressability guarantee */ .text . : { /* Code that needs to be addressable in Real Mode */ *(.text.real) KEEP(*(SORT_BY_NAME(.sort.text.real.*))) *(.rodata.real) KEEP(*(SORT_BY_NAME(.sort.rodata.real.*))) HIDDEN(_ereal = .); /*END: realmode addressability guarantee */ /* Normal Code */ *(.start) KEEP(*(.initprologue)) KEEP(*(SORT_BY_NAME(.init.*))) KEEP(*(SORT_NONE(.init))) KEEP(*(.initepilogue)) KEEP(*(.pltprologue)) *(.plt) KEEP(*(.pltepilogue)) KEEP(*(.pltgotprologue)) *(.plt.got) KEEP(*(.pltgotepilogue)) *(.text.startup .text.startup.*) *(.text.exit .text.exit.*) *(.text.unlikely .text.*_unlikely .text.unlikely.*) *(SORT_BY_ALIGNMENT(.text.antiquity)) *(SORT_BY_ALIGNMENT(.text.antiquity.*)) KEEP(*(.textwindowsprologue)) *(.text.windows) KEEP(*(.textwindowsepilogue)) *(SORT_BY_ALIGNMENT(.text.modernity)) *(SORT_BY_ALIGNMENT(.text.modernity.*)) *(SORT_BY_ALIGNMENT(.text.hot)) *(SORT_BY_ALIGNMENT(.text.hot.*)) KEEP(*(.keep.text)) *(.text .stub .text.*) KEEP(*(SORT_BY_NAME(.sort.text.*))) /* Won't support NX bit DRM for tiny executables */ HIDDEN(.Lape.piro.align = ABSOLUTE(. > APE_PIRO_THRESHOLD ? 0x1000 : 8)); /* Code that musn't be mapped in production */ KEEP(*(.ape.pad.test)); . = ALIGN(.Lape.piro.align); HIDDEN(__test_start = .); *(.test.unlikely) *(.test .test.*) /* Privileged code invulnerable to magic */ KEEP(*(.ape.pad.privileged)); . = ALIGN(.Lape.piro.align); HIDDEN(__privileged_start = .); HIDDEN(__test_end = .); . += 1; *(.privileged) /*BEGIN: Read Only Data */ KEEP(*(.ape.pad.rodata)); . = ALIGN(.Lape.piro.align); . += 1; /* Nonspecific Read-Only Data */ *(.rodata .rodata.*) . += 1; /* Undefined Behavior Sanitizer Types */ HIDDEN(__ubsan_types_start = .); *(.ubsan.types) HIDDEN(__ubsan_types_end = .); . += 1; /* Undefined Behavior Sanitizer Data */ HIDDEN(__ubsan_data_start = .); *(.ubsan.data) HIDDEN(__ubsan_data_end = .); /* Unit Test & Fixture Registry */ /*BEGIN: Read only data that needn't be mapped after initialization */ /* Legal Notices */ KEEP(*(.commentprologue)) KEEP(*(.comment)) KEEP(*(.commentepilogue)) /* Windows DLL Import Directory */ KEEP(*(.idata.ro)); KEEP(*(SORT_BY_NAME(.idata.ro.*))) . += 1; /* Encoded Data Structures w/ Linear Initialization Order */ KEEP(*(.initroprologue)) KEEP(*(SORT_BY_NAME(.initro.*))) KEEP(*(.initroepilogue)) KEEP(*(SORT_BY_NAME(.sort.rodata.*))) KEEP(*(.ape.pad.text)) HIDDEN(.Lape.data.align = ABSOLUTE(PAGESIZE)); . = ALIGN(.Lape.data.align); HIDDEN(_etext = .); PROVIDE_HIDDEN(etext = .); /*END: Read Only Data (only needed for initialization) */ /*END: Read Only Data */ } AT>SmallCode :Rom .data . : { /*BEGIN: Read/Write Data */ KEEP(*(.dataprologue)) *(.data .data.*) KEEP(*(SORT_BY_NAME(.sort.data.*))) . += . > 0 ? 1 : 0; KEEP(*(.gotprologue)) *(.got) KEEP(*(.gotepilogue)) KEEP(*(.gotpltprologue)) *(.got.plt) KEEP(*(.gotpltepilogue)) /*BEGIN: Post-Initialization Read-Only */ . = ALIGN(.Lape.piro.align); HIDDEN(__piro_start = .); QUAD(IMAGE_BASE_VIRTUAL); PROVIDE_HIDDEN(__init_array_start = .); KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) KEEP(*(SORT_NONE(.ctors))) KEEP(*(SORT_NONE(.init_array))) KEEP(*(SORT_NONE(.preinit_array))) PROVIDE_HIDDEN(__init_array_end = .); . += 1; . = ALIGN(__SIZEOF_POINTER__); PROVIDE_HIDDEN(__fini_array_start = .); KEEP(*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) KEEP(*(SORT_NONE(.dtors))) PROVIDE_HIDDEN(__fini_array_end = .); KEEP(*(SORT_BY_NAME(.piro.relo.sort.*))) PROVIDE_HIDDEN(__relo_end = .); KEEP(*(SORT_BY_NAME(.piro.data.sort.*))) KEEP(*(.piro.pad.data)) . = ALIGN(.Lape.data.align); HIDDEN(_edata = .); PROVIDE_HIDDEN(edata = .); } AT>SmallCode :Ram .bss . : { KEEP(*(SORT_BY_NAME(.piro.bss.init.*))) *(.piro.bss) KEEP(*(SORT_BY_NAME(.piro.bss.sort.*))) . += 1; . = ALIGN(.Lape.piro.align); HIDDEN(__piro_end = .); /*END: Post-Initialization Read-Only */ /* Statically Allocated Empty Space */ *(SORT_BY_ALIGNMENT(.bss)) *(SORT_BY_ALIGNMENT(.bss.*)) *(COMMON) KEEP(*(SORT_BY_NAME(.sort.bss.*))) /* eXtreme Low Memory w/ Userspace Remapping */ . = ALIGN(0x1000); *(.xlm) . = ALIGN(0x1000); HIDDEN(_end = .); PROVIDE_HIDDEN(end = .); } AT>SmallCode :Ram /*END: nt addressability guarantee */ /*END: bsd addressability guarantee */ /*END: linux addressability guarantee */ /*END: xnu addressability guarantee */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } .debug 0 : { *(.debug) } .line 0 : { *(.line) } .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } .debug_weaknames 0 : { *(.debug_weaknames) } .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } .debug_pubtypes 0 : { *(.debug_pubtypes) } .debug_ranges 0 : { *(.debug_ranges) } .debug_macro 0 : { *(.debug_macro) } .debug_addr 0 : { *(.debug_addr) } .gnu.attributes 0 : { KEEP(*(.gnu.attributes)) } .GCC.command.line 0 : { *(.GCC.command.line) } /DISCARD/ : { *(.discard) *(.yoink) *(.*) } } PFSTUB8(.Lape.elf.entry, _start); PFSTUB8(.Lape.elf.phoff, RVA(ape.phdrs)); PFSTUB8(.Lape.elf.shoff, 0); PFSTUB4(.Lape.elf.phnum, (.Lape.phdrs.end - ape.phdrs) / 56); PFSTUB4(.Lape.elf.shnum, 0); PFSTUB4(.Lape.elf.shstrndx, 0); SHSTUB2(.Lape.macho.dd.skip, RVA(ape.macho) / 8); SHSTUB2(.Lape.macho.dd.count, (.Lape.macho.end - ape.macho) / 8); PFSTUB4(.Lape.pe.offset, ape.pe - ape.mz); HIDDEN(.Lape.pe.optsz = .Lape.pe.sections - (ape.pe + 24)); HIDDEN(.Lape.pe.shnum = (.Lape.pe.sections_end - .Lape.pe.sections) / 40); HIDDEN(.Lidata.idtsize = idata.idtend - idata.idt); HIDDEN(.Lidata.iatsize = idata.iatend - idata.iat); HIDDEN(.Lape.rom.offset = 0); HIDDEN(.Lape.rom.vaddr = ADDR(.head)); HIDDEN(.Lape.rom.paddr = LOADADDR(.head)); HIDDEN(.Lape.rom.filesz = LOADADDR(.data) - .Lape.rom.paddr); HIDDEN(.Lape.rom.memsz = ADDR(.data) - ADDR(.head)); HIDDEN(.Lape.rom.align = 0x1000); HIDDEN(.Lape.rom.rva = RVA(.Lape.rom.vaddr)); HIDDEN(.Lape.ram.offset = .Lape.rom.offset + .Lape.rom.filesz); HIDDEN(.Lape.ram.vaddr = ADDR(.data)); HIDDEN(.Lape.ram.paddr = LOADADDR(.data)); HIDDEN(.Lape.ram.filesz = LOADADDR(.bss) - LOADADDR(.data)); HIDDEN(.Lape.ram.memsz = ADDR(.bss) + SIZEOF(.bss) - .Lape.ram.vaddr); HIDDEN(.Lape.ram.align = 0x1000); HIDDEN(.Lape.ram.rva = RVA(.Lape.ram.vaddr)); HIDDEN(.Lape.note.offset = .Lape.rom.offset + (.Lape.note - .Lape.rom.vaddr)); HIDDEN(.Lape.note.vaddr = .Lape.note); HIDDEN(.Lape.note.paddr = .Lape.rom.paddr + .Lape.note.offset); HIDDEN(.Lape.note.filesz = .Lape.note.end - .Lape.note); HIDDEN(.Lape.note.memsz = .Lape.note.filesz); HIDDEN(.Lape.note.align = __SIZEOF_POINTER__); HIDDEN(.Lape.text.offset = .Lape.rom.offset + LOADADDR(.text) - .Lape.rom.paddr); HIDDEN(.Lape.text.paddr = LOADADDR(.text)); HIDDEN(.Lape.text.vaddr = ADDR(.text)); HIDDEN(.Lape.text.filesz = SIZEOF(.text)); HIDDEN(.Lape.text.memsz = SIZEOF(.text)); HIDDEN(.Lape.text.align = 4096); HIDDEN(.Lape.text.rva = RVA(.Lape.text.vaddr)); HIDDEN(.Lape.data.offset = .Lape.ram.offset + LOADADDR(.data) - .Lape.ram.paddr); HIDDEN(.Lape.data.paddr = LOADADDR(.data)); HIDDEN(.Lape.data.vaddr = ADDR(.data)); HIDDEN(.Lape.data.filesz = SIZEOF(.data)); HIDDEN(.Lape.data.memsz = SIZEOF(.data)); HIDDEN(.Lape.data.align = 0x1000); HIDDEN(.Lape.data.rva = RVA(.Lape.data.vaddr)); HIDDEN(.Lape.bss.offset = .Lape.ram.offset + LOADADDR(.bss) - .Lape.ram.paddr); HIDDEN(.Lape.bss.paddr = LOADADDR(.bss)); HIDDEN(.Lape.bss.vaddr = ADDR(.bss)); HIDDEN(.Lape.bss.filesz = 0); HIDDEN(.Lape.bss.memsz = SIZEOF(.bss)); HIDDEN(.Lape.bss.align = .Lape.data.align); /* Program Loader Auto-Tune */ HIDDEN(v_ape_realsectors = MIN(REAL_SCRATCH_AREA - IMAGE_BASE_REAL, ROUNDUP(RVA(_edata), 512)) / 512); HIDDEN(v_ape_highsectors = (ROUNDUP(RVA(_edata), 512) / 512) - v_ape_realsectors); /* Windows NT Auto-Subsystem Embedding */ HIDDEN(v_ntsubsystem = (DEFINED(GetMessage) ? kNtImageSubsystemWindowsGui : kNtImageSubsystemWindowsCui)); /* ZIP End of Central Directory header */ #define ZIPCONST(NAME, VAL) HIDDEN(NAME = DEFINED(__zip_start) ? VAL : 0); ZIPCONST(v_zip_cdoffset, __zip_start - IMAGE_BASE_VIRTUAL); ZIPCONST(v_zip_cdirsize, __zip_end - __zip_start); ZIPCONST(v_zip_records, v_zip_cdirsize / kZipCdirHdrLinkableSize); ZIPCONST(v_zip_commentsize, _edata - __zip_end - kZipCdirHdrMinSize); /* Generates deterministic ID for Mach-O. */ #define PHI 0x9e3779b9925d4c17 #define XOR(X,Y) ((X | Y) - (X & Y)) #define XORSHIFT(X,Y) \ X = XOR(X, (Y >> 12)); \ X = XOR(X, (Y << 25)); \ X = XOR(X, (Y >> 27)) #define KMH(X,Y) \ X = (X + (Y >> 000) & 0xFF) * PHI; \ X = (X + (Y >> 010) & 0xFF) * PHI; \ X = (X + (Y >> 020) & 0xFF) * PHI; \ X = (X + (Y >> 030) & 0xFF) * PHI #define BOOP(X) \ XORSHIFT(uuid1_, X); \ KMH(uuid1_, X); \ XORSHIFT(uuid2_, X); \ KMH(uuid2_, X) HIDDEN(uuid1_ = 88172645463325252); HIDDEN(uuid2_ = 88172645463325252); BOOP(.Lape.bss.align); BOOP(.Lape.bss.filesz); BOOP(.Lape.bss.memsz); BOOP(.Lape.bss.offset); BOOP(.Lape.bss.paddr); BOOP(.Lape.data.align); BOOP(.Lape.data.filesz); BOOP(.Lape.data.memsz); BOOP(.Lape.data.offset); BOOP(.Lape.data.paddr); BOOP(.Lape.data.rva); BOOP(.Lape.data.vaddr); BOOP(.Lape.elf.entry); BOOP(.Lape.elf.phnum); BOOP(.Lape.elf.phoff); BOOP(.Lape.elf.shnum); BOOP(.Lape.elf.shoff); BOOP(.Lape.elf.shstrndx); BOOP(.Lape.macho.end); BOOP(.Lape.note); BOOP(.Lape.note.align); BOOP(.Lape.note.end); BOOP(.Lape.note.filesz); BOOP(.Lape.note.memsz); BOOP(.Lape.note.offset); BOOP(.Lape.note.paddr); BOOP(.Lape.note.vaddr); BOOP(.Lape.pe.offset); BOOP(.Lape.pe.optsz); BOOP(.Lape.pe.sections); BOOP(.Lape.pe.sections_end); BOOP(.Lape.pe.shnum); BOOP(.Lape.phdrs.end); BOOP(.Lape.ram.align); BOOP(.Lape.ram.filesz); BOOP(.Lape.ram.memsz); BOOP(.Lape.ram.offset); BOOP(.Lape.ram.paddr); BOOP(.Lape.ram.rva); BOOP(.Lape.ram.vaddr); BOOP(.Lape.rom.align); BOOP(.Lape.rom.filesz); BOOP(.Lape.rom.memsz); BOOP(.Lape.rom.offset); BOOP(.Lape.rom.paddr); BOOP(.Lape.rom.rva); BOOP(.Lape.rom.vaddr); BOOP(.Lape.text.align); BOOP(.Lape.text.filesz); BOOP(.Lape.text.memsz); BOOP(.Lape.text.offset); BOOP(.Lape.text.paddr); BOOP(.Lape.text.rva); BOOP(.Lape.text.vaddr); BOOP(ADDR(.bss)); BOOP(WinMain); BOOP(_start); BOOP(ape.macho); BOOP(ape.mz); BOOP(ape.pe); BOOP(ape.phdrs); BOOP(v_ape_realsectors); ASSERT(ape.mz == IMAGE_BASE_VIRTUAL, "linker panic"); ASSERT((DEFINED(__init_bss_end) ? __init_bss_end : 0) % __SIZEOF_POINTER__ == 0, "__init_bss misalign"); ASSERT(((DEFINED(__init_rodata_end) ? __init_rodata_end : 0) % __SIZEOF_POINTER__ == 0), "__init_rodata misalign"); ASSERT((!DEFINED(ape.grub) ? 1 : RVA(ape.grub) < 8192), "grub stub needs to be in first 8kb of image"); ASSERT(DEFINED(_start) || DEFINED(_start16), "please link a _start() or _start16() entrypoint"); ASSERT(!DEFINED(_start16) || REAL(_end) < 65536, "ape won't support non-tiny real mode programs"); /* Let's not be like Knight Capital. */ /* NOCROSSREFS_TO(.test .text) */ /* ASSERT(ape_sysv_start == .Lape.text.vaddr, */ /* "ape_sysv_start() must be first in .text"); */ #endif /* __LINKER__ */