mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 19:43:32 +00:00
edd9297eba
Your Actually Portable Executables now contains a simple virtual memory that works similarly to the Linux Kernel in the sense that it maps your physical memory to negative addresses. This is needed to support mmap() and malloc(). This functionality has zero code size impact. For example the MODE=tiny LIFE.COM executable is still only 12KB in size. The APE bootloader code has also been simplified to improve readibility and further elevate the elegance by which we're able to support so many platforms thereby enhancing verifiability so that we may engender trust in this bootloading process.
264 lines
9.5 KiB
C
264 lines
9.5 KiB
C
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||
│vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi│
|
||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||
│ │
|
||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||
│ any purpose with or without fee is hereby granted, provided that the │
|
||
│ above copyright notice and this permission notice appear in all copies. │
|
||
│ │
|
||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||
#ifndef APE_MACROS_H_
|
||
#define APE_MACROS_H_
|
||
#include "libc/macros.h"
|
||
#ifdef __ASSEMBLER__
|
||
/* clang-format off */
|
||
|
||
/**
|
||
* @fileoverview Macros relevant to αcτµαlly pδrταblε εxεcµταblε.
|
||
*/
|
||
|
||
// Calls near (i.e. pc+pcrel<64kB) FUNCTION.
|
||
// @mode long,legacy,real
|
||
// @cost 9 bytes overhead
|
||
.macro rlcall function:req
|
||
.byte 0x50 # push %[er]ax
|
||
.byte 0xb8,0,0 # mov $?,%[e]ax
|
||
jmp 911f
|
||
.byte 0x58 # pop %[er]ax
|
||
.byte 0xe8 # call Jvds
|
||
.long \function\()-.-4
|
||
jmp 912f
|
||
911: .byte 0x58 # pop %[er]ax
|
||
.byte 0xe8 # call Jvds
|
||
.short \function\()-.-2
|
||
912:
|
||
.endm
|
||
|
||
// Loads far (i.e. <1mb) abs constexpr ADDRESS into ES:DI+EDX+RDX.
|
||
// @mode long,legacy,real
|
||
.macro movesdi address:req
|
||
.byte 0xbf # mov $0x????xxxx,%[e]di
|
||
.short \address>>4
|
||
.byte 0x8e,0xc7 # mov %di,%es
|
||
.byte 0xbf # mov $0x????xxxx,%[e]di
|
||
.short \address&0xf
|
||
jmp 297f
|
||
.byte 0xbf # mov $0x????xxxx,%edi
|
||
.long \address
|
||
297:
|
||
.endm
|
||
|
||
// Loads 16-bit CONSTEXPR into Qw-register w/ optional zero-extend.
|
||
// @mode long,legacy,real
|
||
.macro bbmov constexpr:req abcd abcd.hi:req abcd.lo:req
|
||
.ifnb \abcd
|
||
.if (\constexpr)<128 && (\constexpr)>=0
|
||
pushpop \constexpr,\abcd
|
||
.exitm
|
||
.endif
|
||
.endif
|
||
movb $(\constexpr)>>8&0xff,\abcd.hi
|
||
movb $(\constexpr)&0xff,\abcd.lo
|
||
.endm
|
||
|
||
// Compares 16-bit CONSTEXPR with Qw-register.
|
||
// @mode long,legacy,real
|
||
.macro bbcmp constexpr:req abcd.hi:req abcd.lo:req
|
||
cmpb $(\constexpr)>>8&0xff,\abcd.hi
|
||
jnz 387f
|
||
cmpb $(\constexpr)&0xff,\abcd.lo
|
||
387:
|
||
.endm
|
||
|
||
// Adds 16-bit CONSTEXPR to Qw-register.
|
||
// @mode long,legacy,real
|
||
.macro bbadd constexpr:req abcd.hi:req abcd.lo:req
|
||
addb $(\constexpr)&0xff,\abcd.lo
|
||
.if (\constexpr) != 0
|
||
adcb $(\constexpr)>>8&0xff,\abcd.hi
|
||
.endif
|
||
.endm
|
||
|
||
// Subtracts 16-bit CONSTEXPR from Qw-register.
|
||
// @mode long,legacy,real
|
||
.macro bbsub constexpr:req abcd.hi:req abcd.lo:req
|
||
subb $(\constexpr)&0xff,\abcd.lo
|
||
.if (\constexpr) != 0
|
||
sbbb $(\constexpr)>>8&0xff,\abcd.hi
|
||
.endif
|
||
.endm
|
||
|
||
// Ands Qw-register with 16-bit CONSTEXPR.
|
||
// @mode long,legacy,real
|
||
.macro bband constexpr:req abcd.hi:req abcd.lo:req
|
||
.if ((\constexpr)&0xff) != 0xff || ((\constexpr)>>8&0xff) == 0xff
|
||
andb $(\constexpr)&0xff,\abcd.lo
|
||
.endif
|
||
.if ((\constexpr)>>8&0xff) != 0xff
|
||
andb $(\constexpr)>>8&0xff,\abcd.hi
|
||
.endif
|
||
.endm
|
||
|
||
// Ors Qw-register with 16-bit CONSTEXPR.
|
||
// @mode long,legacy,real
|
||
.macro bbor constexpr:req abcd.hi:req abcd.lo:req
|
||
.if ((\constexpr)&0xff) != 0 || ((\constexpr)>>8&0xff) != 0
|
||
orb $(\constexpr)&0xff,\abcd.lo
|
||
.endif
|
||
.if ((\constexpr)>>8&0xff) != 0
|
||
orb $(\constexpr)>>8&0xff,\abcd.hi
|
||
.endif
|
||
.endm
|
||
|
||
// Performs ACTION only if in real mode.
|
||
// @mode long,legacy,real
|
||
.macro rlo clobber:req action:vararg
|
||
990: mov $0,\clobber
|
||
.if .-990b!=3
|
||
.error "bad clobber or assembler mode"
|
||
.endif
|
||
991: \action
|
||
.rept 2-(.-991b)
|
||
nop
|
||
.endr
|
||
.if .-991b!=2
|
||
.error "ACTION must be 1-2 bytes"
|
||
.endif
|
||
.endm
|
||
|
||
// Initializes real mode stack.
|
||
// The most holiest of holy code.
|
||
// @mode real
|
||
// @see www.pcjs.org/pubs/pc/reference/intel/8086/
|
||
.macro rlstack seg:req addr:req
|
||
cli
|
||
mov \seg,%ss
|
||
mov \addr,%sp
|
||
sti
|
||
.endm
|
||
|
||
// Symbolic Linker-Defined Binary Content.
|
||
.macro .stub name:req kind:req default type=@object
|
||
.ifnb \default
|
||
.equ \name,\default
|
||
.endif
|
||
.\kind \name
|
||
.type \name,\type
|
||
.weak \name
|
||
.hidden \name
|
||
.endm
|
||
|
||
// Symbolic Linker-Defined Binary-Encoded-Bourne Content.
|
||
// @param units is the number of encoded 32-bit values to insert,
|
||
// e.g. \000 can be encoded as 0x3030305c.
|
||
.macro .shstub name:req num:req
|
||
ss \name,0
|
||
.if \num>1
|
||
ss \name,1
|
||
.if \num>2
|
||
ss \name,2
|
||
ss \name,3
|
||
.if \num>4
|
||
ss \name,4
|
||
ss \name,5
|
||
ss \name,6
|
||
ss \name,7
|
||
.endif
|
||
.endif
|
||
.endif
|
||
.endm
|
||
.macro ss name n
|
||
.stub \name\()_bcs\n,long
|
||
.endm
|
||
|
||
/* clang-format on */
|
||
#elif defined(__LINKER__)
|
||
|
||
#define BCX_NIBBLE(X) ((((X)&0xf) > 0x9) ? ((X)&0xf) + 0x37 : ((X)&0xf) + 0x30)
|
||
#define BCX_OCTET(X) ((BCX_NIBBLE((X) >> 4) << 8) | (BCX_NIBBLE((X) >> 0) << 0))
|
||
#define BCX_INT16(X) ((BCX_OCTET((X) >> 8) << 16) | (BCX_OCTET((X) >> 0) << 0))
|
||
#define BCXSTUB(SYM, X) \
|
||
HIDDEN(SYM##_bcx0 = BCX_INT16((X) >> 48)); \
|
||
HIDDEN(SYM##_bcx1 = BCX_INT16((X) >> 32)); \
|
||
HIDDEN(SYM##_bcx2 = BCX_INT16((X) >> 16)); \
|
||
HIDDEN(SYM##_bcx3 = BCX_INT16((X) >> 0))
|
||
|
||
/**
|
||
* Binary coded backslash octet support.
|
||
*
|
||
* <p>This allows linker scripts to generate printf commands.
|
||
*/
|
||
#define BCO_OCTET(X) (((X)&0x7) + 0x30)
|
||
#define BCOB_UNIT(X) \
|
||
((BCO_OCTET((X) >> 0) << 24) | (BCO_OCTET((X) >> 3) << 16) | \
|
||
(BCO_OCTET(((X)&0xff) >> 6) << 8) | 0x5c)
|
||
|
||
#define PFBYTE(SYM, X, I) HIDDEN(SYM##_bcs##I = BCOB_UNIT((X) >> ((I)*8)))
|
||
#define PFSTUB2(SYM, X) \
|
||
HIDDEN(SYM = (X)); \
|
||
PFBYTE(SYM, X, 0); \
|
||
PFBYTE(SYM, X, 1)
|
||
#define PFSTUB4(SYM, X) \
|
||
PFSTUB2(SYM, X); \
|
||
PFBYTE(SYM, X, 2); \
|
||
PFBYTE(SYM, X, 3)
|
||
#define PFSTUB8(SYM, X) \
|
||
PFSTUB4(SYM, X); \
|
||
PFBYTE(SYM, X, 4); \
|
||
PFBYTE(SYM, X, 5); \
|
||
PFBYTE(SYM, X, 6); \
|
||
PFBYTE(SYM, X, 7)
|
||
|
||
/**
|
||
* Binary coded decimal support.
|
||
*
|
||
* <p>This allows linker scripts to generate dd commands. Leading spaces
|
||
* need to be inserted so Mac doesn't consider them octal; therefore,
|
||
* parameters must be quoted; and eight digits should be good enough.
|
||
*/
|
||
#define SHSTUB2(SYM, X) \
|
||
HIDDEN(SYM##_bcs0 = BCD10K(X)); \
|
||
HIDDEN(SYM##_bcs1 = BCD(X))
|
||
#define BCD(X) \
|
||
((X) == 0 \
|
||
? 0x20202030 \
|
||
: (X) < 10 ? 0x30202020 + (((X) % 10) << 24) \
|
||
: (X) < 100 ? 0x30302020 + (((X) % 10) << 24) + \
|
||
(((X) / 10 % 10) << 16) \
|
||
: (X) < 1000 ? 0x30303020 + (((X) % 10) << 24) + \
|
||
(((X) / 10 % 10) << 16) + \
|
||
(((X) / 100 % 10) << 8) \
|
||
: 0x30303030 + (((X) % 10) << 24) + \
|
||
(((X) / 10 % 10) << 16) + \
|
||
(((X) / 100 % 10) << 8) + \
|
||
(((X) / 1000 % 10) << 0))
|
||
#define BCD10K(X) \
|
||
((X) < 10000 \
|
||
? 0x20202020 \
|
||
: (X) < 100000 \
|
||
? 0x30202020 + (((X) / 10000 % 10) << 24) \
|
||
: (X) < 1000000 \
|
||
? 0x30302020 + (((X) / 10000 % 10) << 24) + \
|
||
(((X) / 100000 % 10) << 16) \
|
||
: (X) < 10000000 \
|
||
? 0x30303020 + (((X) / 10000 % 10) << 24) + \
|
||
(((X) / 100000 % 10) << 16) + \
|
||
(((X) / 1000000 % 10) << 8) \
|
||
: (X) < 100000000 \
|
||
? 0x30303030 + (((X) / 10000 % 10) << 24) + \
|
||
(((X) / 100000 % 10) << 16) + \
|
||
(((X) / 1000000 % 10) << 8) + \
|
||
(((X) / 10000000 % 10) << 0) \
|
||
: 0xffffffffffffffff)
|
||
|
||
#endif /* __ASSEMBLER__ */
|
||
#endif /* APE_MACROS_H_ */
|