663 lines
28 KiB
Plaintext
663 lines
28 KiB
Plaintext
/*-*- 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 embeddings
|
||
|
||
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 */
|
||
#if !defined(IM_FEELING_NAUGHTY) || defined(EMBED_NOTICES)
|
||
KEEP(*(.commentprologue))
|
||
KEEP(*(.comment))
|
||
KEEP(*(.commentepilogue))
|
||
#endif
|
||
|
||
/* 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 CHURN(X) \
|
||
XORSHIFT(uuid1_, X); \
|
||
KMH(uuid1_, X); \
|
||
XORSHIFT(uuid2_, X); \
|
||
KMH(uuid2_, X)
|
||
|
||
HIDDEN(uuid1_ = 88172645463325252);
|
||
HIDDEN(uuid2_ = 88172645463325252);
|
||
|
||
CHURN(.Lape.bss.align);
|
||
CHURN(.Lape.bss.filesz);
|
||
CHURN(.Lape.bss.memsz);
|
||
CHURN(.Lape.bss.offset);
|
||
CHURN(.Lape.bss.paddr);
|
||
CHURN(.Lape.data.align);
|
||
CHURN(.Lape.data.filesz);
|
||
CHURN(.Lape.data.memsz);
|
||
CHURN(.Lape.data.offset);
|
||
CHURN(.Lape.data.paddr);
|
||
CHURN(.Lape.data.rva);
|
||
CHURN(.Lape.data.vaddr);
|
||
CHURN(.Lape.elf.entry);
|
||
CHURN(.Lape.elf.phnum);
|
||
CHURN(.Lape.elf.phoff);
|
||
CHURN(.Lape.elf.shnum);
|
||
CHURN(.Lape.elf.shoff);
|
||
CHURN(.Lape.elf.shstrndx);
|
||
CHURN(.Lape.macho.end);
|
||
CHURN(.Lape.note);
|
||
CHURN(.Lape.note.align);
|
||
CHURN(.Lape.note.end);
|
||
CHURN(.Lape.note.filesz);
|
||
CHURN(.Lape.note.memsz);
|
||
CHURN(.Lape.note.offset);
|
||
CHURN(.Lape.note.paddr);
|
||
CHURN(.Lape.note.vaddr);
|
||
CHURN(.Lape.pe.offset);
|
||
CHURN(.Lape.pe.optsz);
|
||
CHURN(.Lape.pe.sections);
|
||
CHURN(.Lape.pe.sections_end);
|
||
CHURN(.Lape.pe.shnum);
|
||
CHURN(.Lape.phdrs.end);
|
||
CHURN(.Lape.ram.align);
|
||
CHURN(.Lape.ram.filesz);
|
||
CHURN(.Lape.ram.memsz);
|
||
CHURN(.Lape.ram.offset);
|
||
CHURN(.Lape.ram.paddr);
|
||
CHURN(.Lape.ram.rva);
|
||
CHURN(.Lape.ram.vaddr);
|
||
CHURN(.Lape.rom.align);
|
||
CHURN(.Lape.rom.filesz);
|
||
CHURN(.Lape.rom.memsz);
|
||
CHURN(.Lape.rom.offset);
|
||
CHURN(.Lape.rom.paddr);
|
||
CHURN(.Lape.rom.rva);
|
||
CHURN(.Lape.rom.vaddr);
|
||
CHURN(.Lape.text.align);
|
||
CHURN(.Lape.text.filesz);
|
||
CHURN(.Lape.text.memsz);
|
||
CHURN(.Lape.text.offset);
|
||
CHURN(.Lape.text.paddr);
|
||
CHURN(.Lape.text.rva);
|
||
CHURN(.Lape.text.vaddr);
|
||
CHURN(ADDR(.bss));
|
||
CHURN(WinMain);
|
||
CHURN(_start);
|
||
CHURN(ape.macho);
|
||
CHURN(ape.mz);
|
||
CHURN(ape.pe);
|
||
CHURN(ape.phdrs);
|
||
CHURN(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__ */
|