Make minor improvements
- Work towards simplifying ape.S startup process - Rewrote ar because it took minutes to build cosmopolitan.amain
parent
95bc650be8
commit
aea89fe832
166
ape/ape.S
166
ape/ape.S
|
@ -175,7 +175,7 @@ stub: mov $0x40,%dl # *literally* dos
|
||||||
built the last forty years these routines also canonicalize the
|
built the last forty years these routines also canonicalize the
|
||||||
cpu and program state, as it is written in the System V ABI. */
|
cpu and program state, as it is written in the System V ABI. */
|
||||||
|
|
||||||
/ Initializes program and jumps to long mode loader.
|
/ Initializes program and jumps to real mode loader.
|
||||||
/
|
/
|
||||||
/ @param dl drive number (use 0x40 to skip bios disk load)
|
/ @param dl drive number (use 0x40 to skip bios disk load)
|
||||||
/ @mode real
|
/ @mode real
|
||||||
|
@ -188,62 +188,46 @@ pc: cld
|
||||||
#endif
|
#endif
|
||||||
mov $REAL_STACK_FRAME>>4,%di # we need a stack
|
mov $REAL_STACK_FRAME>>4,%di # we need a stack
|
||||||
xor %cx,%cx
|
xor %cx,%cx
|
||||||
|
mov %cx,%es
|
||||||
rlstack %di,%cx
|
rlstack %di,%cx
|
||||||
movpp %cs,%ax # memcpy() [relocate this page]
|
push %cs # memcpy() [relocate this page]
|
||||||
|
pop %ds
|
||||||
call 1f
|
call 1f
|
||||||
1: pop %si
|
1: pop %si
|
||||||
sub $RVA(1b),%si
|
sub $RVA(1b),%si
|
||||||
mov $4,%cl
|
mov $IMAGE_BASE_REAL>>4,%ax
|
||||||
1: shr %si
|
push %ax # save real base
|
||||||
loop 1b
|
push %ax
|
||||||
mov $512,%cx
|
pop %es
|
||||||
mov $IMAGE_BASE_REAL>>4,%di
|
|
||||||
mov %si,%ds
|
|
||||||
mov %di,%es
|
|
||||||
xor %si,%si
|
|
||||||
xor %di,%di
|
xor %di,%di
|
||||||
rep
|
mov $512,%cx
|
||||||
movsb %ds:(%si),%es:(%di)
|
rep movsb
|
||||||
#if USE_SYMBOL_HACK
|
#if USE_SYMBOL_HACK
|
||||||
.byte 0x0f,0x1f,0207 # nop rdi binbase
|
.byte 0x0f,0x1f,0207 # nop rdi binbase
|
||||||
.short (IMAGE_BASE_REAL-0x7c00)/512
|
.short (IMAGE_BASE_REAL-0x7c00)/512
|
||||||
#endif
|
#endif
|
||||||
ljmp $0,$REAL(1f) # longjmp()
|
ljmp $0,$REAL(1f) # longjmp()
|
||||||
1: mov $-512,%cx # memcpy() [relocate this frame]
|
1: mov %cx,%ds # %ds and %cs are now zero
|
||||||
rep
|
mov $XLM_SIZE,%cx # memset to clear real bss
|
||||||
movsb %ds:(%si),%es:(%di)
|
|
||||||
xor %bp,%bp
|
|
||||||
mov %bp,%ds # %ds and %cs are now zero
|
|
||||||
call 1f # setup frame pointers
|
|
||||||
1: push %bp
|
|
||||||
mov %sp,%bp
|
|
||||||
mov $XLM_SIZE,%cx # memset() [clear real bss]
|
|
||||||
mov $XLM_BASE_REAL>>4,%ax
|
mov $XLM_BASE_REAL>>4,%ax
|
||||||
mov %ax,%es
|
mov %ax,%es
|
||||||
xor %ax,%ax
|
xor %ax,%ax
|
||||||
xor %di,%di
|
xor %di,%di
|
||||||
rep
|
rep stosb
|
||||||
stosb %al,%es:(%di)
|
|
||||||
cmp $0x40,%dl # statfs() [disk geometry]
|
cmp $0x40,%dl # statfs() [disk geometry]
|
||||||
je 6f
|
je 6f
|
||||||
call dsknfo
|
call dsknfo
|
||||||
mov $IMAGE_BASE_REAL>>4,%ax
|
pop %es # restore real base
|
||||||
mov %ax,%es
|
mov $1,%al # current sector
|
||||||
mov $v_ape_realsectors,%di # total sectors to read
|
xor %cx,%cx # current cylinder
|
||||||
xor %dh,%dh # current head state
|
xor %dh,%dh # current head
|
||||||
xor %cx,%cx # current cylinder state
|
mov $v_ape_realsectors,%di # total sectors
|
||||||
3: mov %di,%ax
|
3: call pcread
|
||||||
call pcread
|
|
||||||
mov %es,%si
|
|
||||||
4: add $512>>4,%si
|
|
||||||
dec %di
|
dec %di
|
||||||
jz 6f
|
jnz 3b
|
||||||
dec %ax
|
6: mov %ax,XLM(LOADSTATE)+0
|
||||||
jnz 4b
|
mov %cx,XLM(LOADSTATE)+2
|
||||||
mov %si,%es
|
mov %dx,XLM(LOADSTATE)+4
|
||||||
jmp 3b
|
|
||||||
6: mov %cx,XLM(LOADSTATE)+0
|
|
||||||
mov %dx,XLM(LOADSTATE)+2
|
|
||||||
ljmp $0,$REAL(realmodeloader)
|
ljmp $0,$REAL(realmodeloader)
|
||||||
.endfn pc,globl,hidden
|
.endfn pc,globl,hidden
|
||||||
|
|
||||||
|
@ -334,66 +318,40 @@ dsknfo: push %bx
|
||||||
jmp 1b
|
jmp 1b
|
||||||
.endfn dsknfo
|
.endfn dsknfo
|
||||||
|
|
||||||
/ Reads disk sectors via BIOS.
|
/ Reads disk sector via BIOS.
|
||||||
/
|
/
|
||||||
/ Each call to this function performs a single read. It has a
|
/ @param al sector number
|
||||||
/ special ABI, where its parameters are preserved, and rolled
|
|
||||||
/ forward accordingly across calls. BIOS requirements on read
|
|
||||||
/ parameter validity are abstracted. If the requested size is
|
|
||||||
/ too large for one read, then it's tuned down appropriately.
|
|
||||||
/
|
|
||||||
/ Please note that dskinfo() must be called beforehand.
|
|
||||||
/
|
|
||||||
/ @param ax number sectors to read
|
|
||||||
/ @param es destination memory address >> 4
|
/ @param es destination memory address >> 4
|
||||||
/ @param cx cylinder number
|
/ @param cx cylinder number
|
||||||
/ @param dh head number
|
/ @param dh head number
|
||||||
/ @param dl drive number
|
/ @param dl drive number
|
||||||
/ @return number of sectors actually read
|
/ @return number of sectors actually read
|
||||||
pcread: push %bx
|
pcread: push %ax
|
||||||
xor %bx,%bx
|
|
||||||
mov XLM(DRIVE_LAST_SECTOR),%bl
|
|
||||||
cmp %ax,%bx # ax = min(ax, pertrack)
|
|
||||||
ja 1f
|
|
||||||
mov %bx,%ax
|
|
||||||
1: push %cx # how many sectors until 64k
|
|
||||||
push %ax # boundary reads can't cross
|
|
||||||
mov $0x1000,%bx # canonicalizing the segment
|
|
||||||
mov %es,%ax # register is not sufficient
|
|
||||||
sub %ax,%bx
|
|
||||||
and $0x0fff,%bx
|
|
||||||
mov $5,%cx
|
|
||||||
0: shr %bx
|
|
||||||
loop 0b
|
|
||||||
pop %ax
|
|
||||||
pop %cx
|
|
||||||
test %bx,%bx # %es 64k-aligned edge case
|
|
||||||
jz 1f
|
|
||||||
cmp %ax,%bx # ax = min(ax, remain64k)
|
|
||||||
ja 1f
|
|
||||||
mov %bx,%ax
|
|
||||||
1: push %ax # setup int-13-2() params
|
|
||||||
push %cx
|
push %cx
|
||||||
xchg %cl,%ch
|
xchg %cl,%ch
|
||||||
ror %cl
|
ror %cl
|
||||||
ror %cl
|
ror %cl
|
||||||
or $1,%cl # one cylinder at a time
|
or %al,%cl
|
||||||
xor %bx,%bx # es:bx is destination addr
|
xor %bx,%bx # es:bx is destination addr
|
||||||
mov $0x02,%ah # read disk sectors ordinal
|
mov $1,%al # read only one disk sector
|
||||||
|
mov $2,%ah # read disk sectors ordinal
|
||||||
int $0x13
|
int $0x13
|
||||||
pop %cx
|
pop %cx
|
||||||
pop %bx
|
pop %ax
|
||||||
jc 9f
|
jc 9f
|
||||||
mov $0,%ah
|
mov %es,%si
|
||||||
cmp %ax,%bx
|
add $512>>4,%si
|
||||||
jl 9f
|
mov %si,%es
|
||||||
|
inc %al
|
||||||
|
cmp XLM(DRIVE_LAST_SECTOR),%al
|
||||||
|
jbe 2f
|
||||||
|
mov $1,%al
|
||||||
inc %cx
|
inc %cx
|
||||||
cmp XLM(DRIVE_LAST_CYLINDER),%cx
|
cmp XLM(DRIVE_LAST_CYLINDER),%cx
|
||||||
jle 2f
|
jbe 2f
|
||||||
xor %cx,%cx
|
xor %cx,%cx
|
||||||
inc %dh
|
inc %dh
|
||||||
2: pop %bx
|
2: ret
|
||||||
ret
|
|
||||||
9: push %ax
|
9: push %ax
|
||||||
xor %ax,%ax # try disk reset on error
|
xor %ax,%ax # try disk reset on error
|
||||||
int $0x13
|
int $0x13
|
||||||
|
@ -824,11 +782,11 @@ ape.pe: .ascin "PE",4
|
||||||
.long 0 # Checksum
|
.long 0 # Checksum
|
||||||
.short v_ntsubsystem # Subsystem: 0=Neutral,2=GUI,3=Console
|
.short v_ntsubsystem # Subsystem: 0=Neutral,2=GUI,3=Console
|
||||||
.short .LDLLEXE # DllCharacteristics
|
.short .LDLLEXE # DllCharacteristics
|
||||||
.quad 0x0000000000100000 # StackReserve
|
.quad 0x0000000000080000 # StackReserve
|
||||||
.quad 0x0000000000100000 # StackCommit
|
.quad 0x0000000000080000 # StackCommit
|
||||||
.quad 0x0000000000000000 # HeapReserve
|
.quad 0 # HeapReserve
|
||||||
.quad 0x0000000000000000 # HeapCommit
|
.quad 0 # HeapCommit
|
||||||
.long 0x00000000 # LoaderFlags
|
.long 0 # LoaderFlags
|
||||||
.long 16 # NumberOfDirectoryEntries
|
.long 16 # NumberOfDirectoryEntries
|
||||||
.long 0,0 # ExportsDirectory
|
.long 0,0 # ExportsDirectory
|
||||||
.long RVA(idata.idt) # ImportsDirectory
|
.long RVA(idata.idt) # ImportsDirectory
|
||||||
|
@ -857,10 +815,10 @@ ape.pe: .ascin "PE",4
|
||||||
.stub .Lape.text.rva,long # Relative Virtual Address
|
.stub .Lape.text.rva,long # Relative Virtual Address
|
||||||
.stub .Lape.text.filesz,long # Physical Size
|
.stub .Lape.text.filesz,long # Physical Size
|
||||||
.stub .Lape.text.offset,long # Physical Offset
|
.stub .Lape.text.offset,long # Physical Offset
|
||||||
.long 0x00000000 # Relocation Table Offset
|
.long 0 # Relocation Table Offset
|
||||||
.long 0x00000000 # Line Number Table Offset
|
.long 0 # Line Number Table Offset
|
||||||
.short 0x0000 # Relocation Count
|
.short 0 # Relocation Count
|
||||||
.short 0x0000 # Line Number Count
|
.short 0 # Line Number Count
|
||||||
.long .LPETEXT # Flags
|
.long .LPETEXT # Flags
|
||||||
.previous
|
.previous
|
||||||
|
|
||||||
|
@ -870,10 +828,10 @@ ape.pe: .ascin "PE",4
|
||||||
.stub .Lape.ram.rva,long # Relative Virtual Address
|
.stub .Lape.ram.rva,long # Relative Virtual Address
|
||||||
.stub .Lape.ram.filesz,long # Physical Size
|
.stub .Lape.ram.filesz,long # Physical Size
|
||||||
.stub .Lape.ram.offset,long # Physical Offset
|
.stub .Lape.ram.offset,long # Physical Offset
|
||||||
.long 0x00000000 # Relocation Table Offset
|
.long 0 # Relocation Table Offset
|
||||||
.long 0x00000000 # Line Number Table Offset
|
.long 0 # Line Number Table Offset
|
||||||
.short 0x0000 # Relocation Count
|
.short 0 # Relocation Count
|
||||||
.short 0x0000 # Line Number Count
|
.short 0 # Line Number Count
|
||||||
.long .LPEDATA # Flags
|
.long .LPEDATA # Flags
|
||||||
.previous
|
.previous
|
||||||
|
|
||||||
|
@ -1246,7 +1204,8 @@ sflush: mov %si,%cx
|
||||||
mov $UART_TTYIDL,%ah
|
mov $UART_TTYIDL,%ah
|
||||||
1: in %dx,%al
|
1: in %dx,%al
|
||||||
and %ah,%al
|
and %ah,%al
|
||||||
rep nop # todo(jart): interrupts are better
|
rep
|
||||||
|
nop
|
||||||
jz 1b
|
jz 1b
|
||||||
loop 0b
|
loop 0b
|
||||||
2: ret
|
2: ret
|
||||||
|
@ -1269,7 +1228,8 @@ sputc: push %ax
|
||||||
1: in %dx,%al
|
1: in %dx,%al
|
||||||
and %ah,%al
|
and %ah,%al
|
||||||
jnz 2f
|
jnz 2f
|
||||||
rep nop # todo(jart): interrupts are better
|
rep
|
||||||
|
nop
|
||||||
jmp 1b
|
jmp 1b
|
||||||
2: mov %di,%ax
|
2: mov %di,%ax
|
||||||
mov %si,%dx
|
mov %si,%dx
|
||||||
|
@ -1356,7 +1316,7 @@ longmodeloader:
|
||||||
call e820
|
call e820
|
||||||
jc 9f
|
jc 9f
|
||||||
call unreal
|
call unreal
|
||||||
call hiload
|
/ call hiload
|
||||||
jmp golong
|
jmp golong
|
||||||
9: mov $REAL(.Lstr.e820),%ax
|
9: mov $REAL(.Lstr.e820),%ax
|
||||||
call rldie
|
call rldie
|
||||||
|
@ -1478,8 +1438,9 @@ hiload: push %bx
|
||||||
mov $v_ape_highsectors,%di # then copy rest off disk
|
mov $v_ape_highsectors,%di # then copy rest off disk
|
||||||
mov $REAL_SCRATCH_AREA>>4,%ax # to real memory buffer
|
mov $REAL_SCRATCH_AREA>>4,%ax # to real memory buffer
|
||||||
mov %ax,%es
|
mov %ax,%es
|
||||||
mov XLM(LOADSTATE)+0,%cx
|
mov XLM(LOADSTATE)+0,%ax
|
||||||
mov XLM(LOADSTATE)+2,%dx
|
mov XLM(LOADSTATE)+2,%cx
|
||||||
|
mov XLM(LOADSTATE)+4,%dx
|
||||||
0: test %di,%di
|
0: test %di,%di
|
||||||
jz 9f
|
jz 9f
|
||||||
mov %di,%ax
|
mov %di,%ax
|
||||||
|
@ -1590,6 +1551,7 @@ pinit: push %ds
|
||||||
add $0x1000,%eax
|
add $0x1000,%eax
|
||||||
add $8,%si
|
add $8,%si
|
||||||
loop 0b
|
loop 0b
|
||||||
|
movb $0,0 # unmap null
|
||||||
pop %ds
|
pop %ds
|
||||||
movl $TIP-0x4000,XLM(PAGE_TABLE_STACK_POINTER) # STACK→XLM
|
movl $TIP-0x4000,XLM(PAGE_TABLE_STACK_POINTER) # STACK→XLM
|
||||||
mov $TIP-0x1000,%eax # PML4T→CR3
|
mov $TIP-0x1000,%eax # PML4T→CR3
|
||||||
|
@ -1631,13 +1593,13 @@ long: push $GDT_LONG_DATA
|
||||||
xor %ebp,%ebp
|
xor %ebp,%ebp
|
||||||
mov $REAL_STACK_FRAME+FRAMESIZE,%esp
|
mov $REAL_STACK_FRAME+FRAMESIZE,%esp
|
||||||
call __map_image
|
call __map_image
|
||||||
ezlea _metal,ax
|
ezlea metal,ax
|
||||||
jmp *%rax
|
jmp *%rax
|
||||||
.endfn long
|
.endfn long
|
||||||
|
|
||||||
/ Long mode in virtual address space.
|
/ Long mode in virtual address space.
|
||||||
/ @noreturn
|
/ @noreturn
|
||||||
_metal:
|
metal:
|
||||||
#if USE_SYMBOL_HACK
|
#if USE_SYMBOL_HACK
|
||||||
.byte 0x0f,0x1f,0207 # nop rdi binbase
|
.byte 0x0f,0x1f,0207 # nop rdi binbase
|
||||||
.long (IMAGE_BASE_VIRTUAL-IMAGE_BASE_REAL)/512
|
.long (IMAGE_BASE_VIRTUAL-IMAGE_BASE_REAL)/512
|
||||||
|
@ -1658,7 +1620,7 @@ _metal:
|
||||||
push $0 # argc
|
push $0 # argc
|
||||||
xor %edi,%edi
|
xor %edi,%edi
|
||||||
jmp _start
|
jmp _start
|
||||||
.endfn _metal
|
.endfn metal
|
||||||
|
|
||||||
/ Avoid linker script variables appearing as code in objdump.
|
/ Avoid linker script variables appearing as code in objdump.
|
||||||
.macro .ldsvar name:req
|
.macro .ldsvar name:req
|
||||||
|
|
|
@ -537,7 +537,8 @@ HIDDEN(.Lape.bss.align = .Lape.data.align);
|
||||||
/* Program Loader Auto-Tune */
|
/* Program Loader Auto-Tune */
|
||||||
HIDDEN(v_ape_realsectors =
|
HIDDEN(v_ape_realsectors =
|
||||||
MIN(REAL_SCRATCH_AREA - IMAGE_BASE_REAL,
|
MIN(REAL_SCRATCH_AREA - IMAGE_BASE_REAL,
|
||||||
ROUNDUP(RVA(_edata), 512)) / 512);
|
ROUNDUP(RVA(_edata), 4096)) / 512);
|
||||||
|
HIDDEN(v_ape_realpages = v_ape_realsectors / (4096 / 512));
|
||||||
HIDDEN(v_ape_highsectors =
|
HIDDEN(v_ape_highsectors =
|
||||||
(ROUNDUP(RVA(_edata), 512) / 512) - v_ape_realsectors);
|
(ROUNDUP(RVA(_edata), 512) / 512) - v_ape_realsectors);
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@
|
||||||
#define XLM_BADIDT 0x2230
|
#define XLM_BADIDT 0x2230
|
||||||
#define XLM_BADIDT_SIZE 6
|
#define XLM_BADIDT_SIZE 6
|
||||||
#define XLM_LOADSTATE 0x2240
|
#define XLM_LOADSTATE 0x2240
|
||||||
#define XLM_LOADSTATE_SIZE 4
|
#define XLM_LOADSTATE_SIZE 6
|
||||||
#define XLM_SIZE ROUNDUP(XLM_LOADSTATE + XLM_LOADSTATE_SIZE, 0x1000)
|
#define XLM_SIZE ROUNDUP(XLM_LOADSTATE + XLM_LOADSTATE_SIZE, 0x1000)
|
||||||
#define IMAGE_BASE_REAL (XLM_BASE_REAL + XLM_SIZE)
|
#define IMAGE_BASE_REAL (XLM_BASE_REAL + XLM_SIZE)
|
||||||
|
|
||||||
|
|
|
@ -25,12 +25,11 @@ textreal static void __map_segment(uint64_t k, uint64_t a, uint64_t b) {
|
||||||
uint64_t *e;
|
uint64_t *e;
|
||||||
for (; a < b; a += 0x1000) {
|
for (; a < b; a += 0x1000) {
|
||||||
e = getpagetableentry(IMAGE_BASE_VIRTUAL + a, 3, &g_pml4t, &g_ptsp_xlm);
|
e = getpagetableentry(IMAGE_BASE_VIRTUAL + a, 3, &g_pml4t, &g_ptsp_xlm);
|
||||||
*e = (IMAGE_BASE_PHYSICAL + a) | k;
|
*e = (IMAGE_BASE_REAL + a) | k;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
textreal void __map_image(void) {
|
textreal void __map_image(void) {
|
||||||
pageunmap(0);
|
|
||||||
__map_segment(PAGE_V | PAGE_U, 0, (uintptr_t)_etext - IMAGE_BASE_VIRTUAL);
|
__map_segment(PAGE_V | PAGE_U, 0, (uintptr_t)_etext - IMAGE_BASE_VIRTUAL);
|
||||||
__map_segment(PAGE_V | PAGE_U | PAGE_RW | PAGE_XD,
|
__map_segment(PAGE_V | PAGE_U | PAGE_RW | PAGE_XD,
|
||||||
(uintptr_t)_etext - IMAGE_BASE_VIRTUAL,
|
(uintptr_t)_etext - IMAGE_BASE_VIRTUAL,
|
||||||
|
|
|
@ -4,57 +4,28 @@
|
||||||
#
|
#
|
||||||
# OVERVIEW
|
# OVERVIEW
|
||||||
#
|
#
|
||||||
# GNU Archiver Veneer
|
# Cosmopolitan Archiver
|
||||||
#
|
#
|
||||||
# DESCRIPTION
|
# DESCRIPTION
|
||||||
#
|
#
|
||||||
# This script wraps normal archive commands that're transparently
|
# This goes 100x faster than ar and ranlib.
|
||||||
# passed-through. It adds value too, by addressing difficulties
|
|
||||||
# that would normally cause a developer to need `make clean`.
|
|
||||||
#
|
#
|
||||||
# EXAMPLE
|
# EXAMPLE
|
||||||
#
|
#
|
||||||
# build/archive ar rcsD library.a foo.o ...
|
# build/archive rcsD library.a foo.o ...
|
||||||
|
|
||||||
if [ ! -d o/third_party/gcc ]; then
|
|
||||||
third_party/gcc/unbundle.sh
|
|
||||||
fi
|
|
||||||
|
|
||||||
export LC_ALL=C
|
|
||||||
RM=${RM:-$(command -v rm) -f} || exit
|
|
||||||
MKDIR=${MKDIR:-$(command -v mkdir) -p} || exit
|
MKDIR=${MKDIR:-$(command -v mkdir) -p} || exit
|
||||||
|
# if [ -x "o/$MODE/tool/build/ar.com" ]; then
|
||||||
AR=$1
|
# set -- "o/$MODE/tool/build/ar.com" "$@"
|
||||||
ARFLAGS=$2
|
# else
|
||||||
OUT=$3
|
if [ ! -x o/build/bootstrap/ar.com ]; then
|
||||||
shift 3
|
mkdir -p o/build/bootstrap &&
|
||||||
|
cp -f build/bootstrap/ar.com o/build/bootstrap/ar.com.$$ &&
|
||||||
# remove directory arguments (having .a targets depend on dirs is what
|
mv -f o/build/bootstrap/ar.com.$$ o/build/bootstrap/ar.com || exit
|
||||||
# lets them be invalidated by deleted files)
|
|
||||||
FIRST=1
|
|
||||||
for x; do
|
|
||||||
if [ $FIRST -eq 1 ]; then
|
|
||||||
set --
|
|
||||||
FIRST=0
|
|
||||||
fi
|
|
||||||
if [ -d "$x" ]; then
|
|
||||||
if [ -f "$OUT" ] && [ "$x" -nt "$OUT" ]; then
|
|
||||||
$RM "$OUT"
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [ "$x" != "${x%.o}" ]; then
|
|
||||||
set -- "$@" "$x"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
set -- "$AR" "$ARFLAGS" "$OUT" "$@"
|
|
||||||
printf %s\\n "$*" >"$OUT.cmd"
|
|
||||||
|
|
||||||
OUTDIR="${OUT%/*}"
|
|
||||||
if [ "$OUTDIR" != "$OUT" ] && [ ! -d "$OUTDIR" ]; then
|
|
||||||
$MKDIR "$OUTDIR" || exit 2
|
|
||||||
fi
|
fi
|
||||||
|
set -- o/build/bootstrap/ar.com "$@"
|
||||||
|
# fi
|
||||||
|
OUT=$3
|
||||||
|
|
||||||
printf "$LOGFMT" "${ACTION:-ARCHIVE.a}" "$OUT" >&2
|
printf "$LOGFMT" "${ACTION:-ARCHIVE.a}" "$OUT" >&2
|
||||||
# if [ "$SILENT" = "0" ]; then
|
# if [ "$SILENT" = "0" ]; then
|
||||||
|
|
Binary file not shown.
|
@ -65,7 +65,7 @@ CC = o/third_party/gcc/bin/x86_64-linux-musl-gcc
|
||||||
CXX = o/third_party/gcc/bin/x86_64-linux-musl-g++
|
CXX = o/third_party/gcc/bin/x86_64-linux-musl-g++
|
||||||
CXXFILT = o/third_party/gcc/bin/x86_64-linux-musl-c++filt
|
CXXFILT = o/third_party/gcc/bin/x86_64-linux-musl-c++filt
|
||||||
LD = o/third_party/gcc/bin/x86_64-linux-musl-ld.bfd
|
LD = o/third_party/gcc/bin/x86_64-linux-musl-ld.bfd
|
||||||
AR = o/third_party/gcc/bin/x86_64-linux-musl-ar
|
AR = build/archive
|
||||||
NM = o/third_party/gcc/bin/x86_64-linux-musl-nm
|
NM = o/third_party/gcc/bin/x86_64-linux-musl-nm
|
||||||
GCC = o/third_party/gcc/bin/x86_64-linux-musl-gcc
|
GCC = o/third_party/gcc/bin/x86_64-linux-musl-gcc
|
||||||
STRIP = o/third_party/gcc/bin/x86_64-linux-musl-strip
|
STRIP = o/third_party/gcc/bin/x86_64-linux-musl-strip
|
||||||
|
@ -295,7 +295,7 @@ PREPROCESS.lds = $(CC) $(PREPROCESS.lds.flags)
|
||||||
LINK = build/link $(LD) $(LINK.flags)
|
LINK = build/link $(LD) $(LINK.flags)
|
||||||
ELF = o/libc/elf/elf.lds
|
ELF = o/libc/elf/elf.lds
|
||||||
ELFLINK = ACTION=LINK.elf $(LINK) $(LINKARGS) $(OUTPUT_OPTION)
|
ELFLINK = ACTION=LINK.elf $(LINK) $(LINKARGS) $(OUTPUT_OPTION)
|
||||||
ARCHIVE = build/archive $(AR) $(ARFLAGS)
|
ARCHIVE = $(AR) $(ARFLAGS)
|
||||||
LINKARGS = $(patsubst %.lds,-T %.lds,$(call uniqr,$(LD.libs) $(filter-out %.pkg,$^)))
|
LINKARGS = $(patsubst %.lds,-T %.lds,$(call uniqr,$(LD.libs) $(filter-out %.pkg,$^)))
|
||||||
LOLSAN = build/lolsan -b $(IMAGE_BASE_VIRTUAL)
|
LOLSAN = build/lolsan -b $(IMAGE_BASE_VIRTUAL)
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ int main(int argc, char *argv[]) {
|
||||||
(tab = OpenSymbolTable(filename))) {
|
(tab = OpenSymbolTable(filename))) {
|
||||||
for (unsigned i = 0; i < tab->count; ++i) {
|
for (unsigned i = 0; i < tab->count; ++i) {
|
||||||
printf("%p %s\n", tab->addr_base + tab->symbols[i].addr_rva,
|
printf("%p %s\n", tab->addr_base + tab->symbols[i].addr_rva,
|
||||||
getelfstring(tab->elf, tab->elfsize, tab->name_base,
|
GetElfString(tab->elf, tab->elfsize, tab->name_base,
|
||||||
tab->symbols[i].name_rva));
|
tab->symbols[i].name_rva));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -148,6 +148,36 @@ unsigned long hamming(unsigned long, unsigned long) pureconst;
|
||||||
Ple[7] = (uint8_t)(Vle >> 070); \
|
Ple[7] = (uint8_t)(Vle >> 070); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define WRITE16BE(P, V) \
|
||||||
|
do { \
|
||||||
|
uint8_t *Ple = (uint8_t *)(P); \
|
||||||
|
uint16_t Vle = (V); \
|
||||||
|
Ple[1] = (uint8_t)(Vle >> 000); \
|
||||||
|
Ple[0] = (uint8_t)(Vle >> 010); \
|
||||||
|
} while (0)
|
||||||
|
#define WRITE32BE(P, V) \
|
||||||
|
do { \
|
||||||
|
uint8_t *Ple = (uint8_t *)(P); \
|
||||||
|
uint32_t Vle = (V); \
|
||||||
|
Ple[3] = (uint8_t)(Vle >> 000); \
|
||||||
|
Ple[2] = (uint8_t)(Vle >> 010); \
|
||||||
|
Ple[1] = (uint8_t)(Vle >> 020); \
|
||||||
|
Ple[0] = (uint8_t)(Vle >> 030); \
|
||||||
|
} while (0)
|
||||||
|
#define WRITE64BE(P, V) \
|
||||||
|
do { \
|
||||||
|
uint8_t *Ple = (uint8_t *)(P); \
|
||||||
|
uint64_t Vle = (V); \
|
||||||
|
Ple[7] = (uint8_t)(Vle >> 000); \
|
||||||
|
Ple[6] = (uint8_t)(Vle >> 010); \
|
||||||
|
Ple[5] = (uint8_t)(Vle >> 020); \
|
||||||
|
Ple[4] = (uint8_t)(Vle >> 030); \
|
||||||
|
Ple[3] = (uint8_t)(Vle >> 040); \
|
||||||
|
Ple[2] = (uint8_t)(Vle >> 050); \
|
||||||
|
Ple[1] = (uint8_t)(Vle >> 060); \
|
||||||
|
Ple[0] = (uint8_t)(Vle >> 070); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
│ cosmopolitan § bits » some assembly required ─╬─│┼
|
│ cosmopolitan § bits » some assembly required ─╬─│┼
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||||
|
|
|
@ -79,12 +79,12 @@ bool isexecutable(const char *);
|
||||||
bool isregularfile(const char *);
|
bool isregularfile(const char *);
|
||||||
bool32 isatty(int) nosideeffect;
|
bool32 isatty(int) nosideeffect;
|
||||||
bool32 ischardev(int) nosideeffect;
|
bool32 ischardev(int) nosideeffect;
|
||||||
|
char *commandv(const char *, char[hasatleast PATH_MAX]);
|
||||||
char *get_current_dir_name(void) nodiscard;
|
char *get_current_dir_name(void) nodiscard;
|
||||||
char *getcwd(char *, size_t);
|
char *getcwd(char *, size_t);
|
||||||
char *realpath(const char *, char *);
|
char *realpath(const char *, char *);
|
||||||
char *replaceuser(const char *) nodiscard;
|
char *replaceuser(const char *) nodiscard;
|
||||||
char *ttyname(int);
|
char *ttyname(int);
|
||||||
char *commandv(const char *, char[hasatleast PATH_MAX]);
|
|
||||||
int access(const char *, int) nothrow;
|
int access(const char *, int) nothrow;
|
||||||
int arch_prctl();
|
int arch_prctl();
|
||||||
int chdir(const char *);
|
int chdir(const char *);
|
||||||
|
@ -120,6 +120,8 @@ int fstat(int, struct stat *);
|
||||||
int fstatat(int, const char *, struct stat *, uint32_t);
|
int fstatat(int, const char *, struct stat *, uint32_t);
|
||||||
int fsync(int);
|
int fsync(int);
|
||||||
int ftruncate(int, int64_t);
|
int ftruncate(int, int64_t);
|
||||||
|
int getdomainname(char *, size_t);
|
||||||
|
int gethostname(char *, size_t);
|
||||||
int getppid(void);
|
int getppid(void);
|
||||||
int getpriority(int, unsigned);
|
int getpriority(int, unsigned);
|
||||||
int getrlimit(int, struct rlimit *);
|
int getrlimit(int, struct rlimit *);
|
||||||
|
@ -161,18 +163,18 @@ int rmdir(const char *);
|
||||||
int sched_getaffinity(int, uint64_t, void *);
|
int sched_getaffinity(int, uint64_t, void *);
|
||||||
int sched_setaffinity(int, uint64_t, const void *);
|
int sched_setaffinity(int, uint64_t, const void *);
|
||||||
int sched_yield(void);
|
int sched_yield(void);
|
||||||
|
int setegid(uint32_t);
|
||||||
|
int seteuid(uint32_t);
|
||||||
|
int setgid(uint32_t);
|
||||||
int setpgid(int, int);
|
int setpgid(int, int);
|
||||||
int setpriority(int, unsigned, int);
|
int setpriority(int, unsigned, int);
|
||||||
|
int setregid(uint32_t, uint32_t);
|
||||||
|
int setresgid(uint32_t, uint32_t, uint32_t);
|
||||||
|
int setresuid(uint32_t, uint32_t, uint32_t);
|
||||||
|
int setreuid(uint32_t, uint32_t);
|
||||||
int setrlimit(int, const struct rlimit *);
|
int setrlimit(int, const struct rlimit *);
|
||||||
int setsid(void);
|
int setsid(void);
|
||||||
int setuid(uint32_t);
|
int setuid(uint32_t);
|
||||||
int setgid(uint32_t);
|
|
||||||
int seteuid(uint32_t);
|
|
||||||
int setegid(uint32_t);
|
|
||||||
int setreuid(uint32_t, uint32_t);
|
|
||||||
int setregid(uint32_t, uint32_t);
|
|
||||||
int setresuid(uint32_t, uint32_t, uint32_t);
|
|
||||||
int setresgid(uint32_t, uint32_t, uint32_t);
|
|
||||||
int sigaction(int, const struct sigaction *, struct sigaction *);
|
int sigaction(int, const struct sigaction *, struct sigaction *);
|
||||||
int sigignore(int);
|
int sigignore(int);
|
||||||
int sigprocmask(int, const struct sigset *, struct sigset *);
|
int sigprocmask(int, const struct sigset *, struct sigset *);
|
||||||
|
@ -200,6 +202,7 @@ int64_t preadv(int, struct iovec *, int, int64_t);
|
||||||
int64_t pwrite(int, const void *, size_t, int64_t);
|
int64_t pwrite(int, const void *, size_t, int64_t);
|
||||||
int64_t pwritev(int, const struct iovec *, int, int64_t);
|
int64_t pwritev(int, const struct iovec *, int, int64_t);
|
||||||
int64_t syscall();
|
int64_t syscall();
|
||||||
|
void sync(void);
|
||||||
long telldir(DIR *);
|
long telldir(DIR *);
|
||||||
int getpid(void);
|
int getpid(void);
|
||||||
long times(struct tms *);
|
long times(struct tms *);
|
||||||
|
|
|
@ -16,10 +16,10 @@ LIBC_CALLS_ARTIFACTS += LIBC_CALLS_A
|
||||||
LIBC_CALLS = $(LIBC_CALLS_A_DEPS) $(LIBC_CALLS_A)
|
LIBC_CALLS = $(LIBC_CALLS_A_DEPS) $(LIBC_CALLS_A)
|
||||||
LIBC_CALLS_A = o/$(MODE)/libc/calls/syscalls.a
|
LIBC_CALLS_A = o/$(MODE)/libc/calls/syscalls.a
|
||||||
LIBC_CALLS_A_FILES := \
|
LIBC_CALLS_A_FILES := \
|
||||||
|
$(wildcard libc/calls/*) \
|
||||||
$(wildcard libc/calls/typedef/*) \
|
$(wildcard libc/calls/typedef/*) \
|
||||||
$(wildcard libc/calls/thunks/*) \
|
$(wildcard libc/calls/thunks/*) \
|
||||||
$(wildcard libc/calls/struct/*) \
|
$(wildcard libc/calls/struct/*)
|
||||||
$(wildcard libc/calls/*)
|
|
||||||
LIBC_CALLS_A_HDRS = $(filter %.h,$(LIBC_CALLS_A_FILES))
|
LIBC_CALLS_A_HDRS = $(filter %.h,$(LIBC_CALLS_A_FILES))
|
||||||
LIBC_CALLS_A_SRCS_S = $(filter %.S,$(LIBC_CALLS_A_FILES))
|
LIBC_CALLS_A_SRCS_S = $(filter %.S,$(LIBC_CALLS_A_FILES))
|
||||||
LIBC_CALLS_A_SRCS_C = $(filter %.c,$(LIBC_CALLS_A_FILES))
|
LIBC_CALLS_A_SRCS_C = $(filter %.c,$(LIBC_CALLS_A_FILES))
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=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 │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/calls/struct/utsname.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/macros.h"
|
||||||
|
#include "libc/nt/enum/computernameformat.h"
|
||||||
|
#include "libc/nt/errors.h"
|
||||||
|
#include "libc/nt/runtime.h"
|
||||||
|
#include "libc/nt/systeminfo.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
|
int getdomainname(char *name, size_t len) {
|
||||||
|
uint32_t nSize;
|
||||||
|
char16_t name16[256];
|
||||||
|
struct utsname u;
|
||||||
|
if (len < 1) return einval();
|
||||||
|
if (!name) return efault();
|
||||||
|
if (!IsWindows()) {
|
||||||
|
if (uname(&u) == -1) return -1;
|
||||||
|
if (!memccpy(name, u.domainname[0] ? u.domainname : u.nodename, '\0',
|
||||||
|
len)) {
|
||||||
|
name[len - 1] = '\0';
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
nSize = ARRAYLEN(name16);
|
||||||
|
if (!GetComputerNameEx(kNtComputerNameDnsFullyQualified, name16, &nSize)) {
|
||||||
|
return winerr();
|
||||||
|
}
|
||||||
|
tprecode16to8(name, MIN(MIN(ARRAYLEN(name16), nSize + 1), len), name16);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=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 │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/calls/struct/utsname.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/macros.h"
|
||||||
|
#include "libc/nt/enum/computernameformat.h"
|
||||||
|
#include "libc/nt/errors.h"
|
||||||
|
#include "libc/nt/runtime.h"
|
||||||
|
#include "libc/nt/systeminfo.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns name of host system, e.g.
|
||||||
|
*
|
||||||
|
* pheidippides.domain.example
|
||||||
|
* ^^^^^^^^^^^^
|
||||||
|
*/
|
||||||
|
int gethostname(char *name, size_t len) {
|
||||||
|
uint32_t nSize;
|
||||||
|
char16_t name16[256];
|
||||||
|
struct utsname u;
|
||||||
|
if (len < 1) return einval();
|
||||||
|
if (!name) return efault();
|
||||||
|
if (!IsWindows()) {
|
||||||
|
if (uname(&u) == -1) return -1;
|
||||||
|
if (!memccpy(name, u.nodename, '\0', len)) {
|
||||||
|
name[len - 1] = '\0';
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
nSize = ARRAYLEN(name16);
|
||||||
|
if (!GetComputerNameEx(kNtComputerNameDnsHostname, name16, &nSize)) {
|
||||||
|
return winerr();
|
||||||
|
}
|
||||||
|
tprecode16to8(name, MIN(MIN(ARRAYLEN(name16), nSize + 1), len), name16);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -49,7 +49,7 @@ __getntsyspath:
|
||||||
cmpb $'\\,-1(%rdi)
|
cmpb $'\\,-1(%rdi)
|
||||||
jne 2f
|
jne 2f
|
||||||
movb $'/,-1(%rdi)
|
movb $'/,-1(%rdi)
|
||||||
2: loop 1b
|
2: .loop 1b
|
||||||
leave
|
leave
|
||||||
ret
|
ret
|
||||||
.endfn __getntsyspath,globl,hidden
|
.endfn __getntsyspath,globl,hidden
|
||||||
|
|
|
@ -161,6 +161,7 @@ i32 sigaction$sysv(i32, const void *, void *, i64) hidden;
|
||||||
i32 sigprocmask$sysv(i32, const sigset *, sigset *, u64) hidden;
|
i32 sigprocmask$sysv(i32, const sigset *, sigset *, u64) hidden;
|
||||||
i32 sigsuspend$sysv(const sigset *, u64) hidden;
|
i32 sigsuspend$sysv(const sigset *, u64) hidden;
|
||||||
i32 symlinkat$sysv(const char *, i32, const char *) hidden;
|
i32 symlinkat$sysv(const char *, i32, const char *) hidden;
|
||||||
|
i32 sync$sysv(void) hidden;
|
||||||
i32 sync_file_range$sysv(i32, i64, i64, u32) hidden;
|
i32 sync_file_range$sysv(i32, i64, i64, u32) hidden;
|
||||||
i32 sysinfo$sysv(struct sysinfo *) hidden;
|
i32 sysinfo$sysv(struct sysinfo *) hidden;
|
||||||
i32 truncate$sysv(const char *, u64) hidden;
|
i32 truncate$sysv(const char *, u64) hidden;
|
||||||
|
@ -239,6 +240,7 @@ int rename$nt(const char *, const char *) hidden;
|
||||||
int rmdir$nt(const char *) hidden;
|
int rmdir$nt(const char *) hidden;
|
||||||
int sched_yield$nt(void) hidden;
|
int sched_yield$nt(void) hidden;
|
||||||
int stat$nt(const char *, struct stat *) hidden;
|
int stat$nt(const char *, struct stat *) hidden;
|
||||||
|
int sync$nt(void) hidden;
|
||||||
int symlink$nt(const char *, const char *) hidden;
|
int symlink$nt(const char *, const char *) hidden;
|
||||||
int sysinfo$nt(struct sysinfo *) hidden;
|
int sysinfo$nt(struct sysinfo *) hidden;
|
||||||
int truncate$nt(const char *, u64) hidden;
|
int truncate$nt(const char *, u64) hidden;
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/sysv/consts/at.h"
|
#include "libc/sysv/consts/at.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renames files relative to directories.
|
||||||
|
*/
|
||||||
int renameat(int olddirfd, const char *oldpath, int newdirfd,
|
int renameat(int olddirfd, const char *oldpath, int newdirfd,
|
||||||
const char *newpath) {
|
const char *newpath) {
|
||||||
unsigned mode;
|
unsigned mode;
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=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 │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/internal.h"
|
||||||
|
#include "libc/nt/createfile.h"
|
||||||
|
#include "libc/nt/files.h"
|
||||||
|
#include "libc/nt/runtime.h"
|
||||||
|
#include "libc/sysv/consts/ok.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flushes all open file handles and, if possible, all disk drives.
|
||||||
|
*/
|
||||||
|
int sync$nt(void) {
|
||||||
|
unsigned i;
|
||||||
|
int64_t volume;
|
||||||
|
uint32_t drives;
|
||||||
|
char16_t path[] = u"\\\\.\\C:";
|
||||||
|
for (i = 0; i < g_fds.n; ++i) {
|
||||||
|
if (g_fds.p[i].kind == kFdFile) {
|
||||||
|
FlushFileBuffers(g_fds.p[i].handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (drives = GetLogicalDrives(), i = 0; i <= 'Z' - 'A'; ++i) {
|
||||||
|
if (!(drives & (1 << i))) continue;
|
||||||
|
path[4] = 'A' + i;
|
||||||
|
if (ntaccesscheck(path, R_OK | W_OK) != -1) {
|
||||||
|
if ((volume = CreateFile(
|
||||||
|
path, kNtFileReadAttributes,
|
||||||
|
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, 0,
|
||||||
|
kNtOpenExisting, 0, 0)) != -1) {
|
||||||
|
FlushFileBuffers(volume);
|
||||||
|
CloseHandle(volume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -18,19 +18,16 @@
|
||||||
│ 02110-1301 USA │
|
│ 02110-1301 USA │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/sysv/consts/map.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/sysv/consts/prot.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocates deterministic stack for process.
|
* Flushes file system changes to disk to the greatest extent possible.
|
||||||
* @see _executive()
|
|
||||||
*/
|
*/
|
||||||
void *_getstack(void) {
|
void sync(void) {
|
||||||
char *p;
|
if (!IsWindows()) {
|
||||||
p = mmap((char *)0x700000000000 /* IMAGE_BASE_VIRTUAL */ - STACKSIZE,
|
sync$sysv();
|
||||||
STACKSIZE, PROT_READ | PROT_WRITE,
|
} else {
|
||||||
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
sync$nt();
|
||||||
if (p == MAP_FAILED) abort();
|
}
|
||||||
return p + STACKSIZE;
|
|
||||||
}
|
}
|
|
@ -22,6 +22,7 @@ size_t int64toarray_radix10(int64_t, char[hasatleast 21]);
|
||||||
size_t uint64toarray_radix10(uint64_t, char[hasatleast 21]);
|
size_t uint64toarray_radix10(uint64_t, char[hasatleast 21]);
|
||||||
size_t uint64toarray_radix16(uint64_t, char[hasatleast 17]);
|
size_t uint64toarray_radix16(uint64_t, char[hasatleast 17]);
|
||||||
size_t uint64toarray_fixed16(uint64_t, char[hasatleast 17], uint8_t);
|
size_t uint64toarray_fixed16(uint64_t, char[hasatleast 17], uint8_t);
|
||||||
|
size_t uint64toarray_radix8(uint64_t, char[hasatleast 24]);
|
||||||
|
|
||||||
#ifndef __STRICT_ANSI__
|
#ifndef __STRICT_ANSI__
|
||||||
size_t int128toarray_radix10(int128_t, char *);
|
size_t int128toarray_radix10(int128_t, char *);
|
||||||
|
|
|
@ -17,21 +17,24 @@
|
||||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||||
│ 02110-1301 USA │
|
│ 02110-1301 USA │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/elf/def.h"
|
#include "libc/alg/reverse.h"
|
||||||
#include "libc/elf/elf.h"
|
#include "libc/conv/conv.h"
|
||||||
|
#include "libc/conv/itoa.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
|
|
||||||
Elf64_Shdr *getelfsectionbyaddress(const Elf64_Ehdr *elf, size_t mapsize,
|
/**
|
||||||
void *addr) {
|
* Converts unsigned 64-bit integer to octal string.
|
||||||
Elf64_Half i;
|
* @param a needs at least 24 bytes
|
||||||
Elf64_Shdr *shdr;
|
* @return bytes written w/o nul
|
||||||
if (elf) {
|
*/
|
||||||
for (i = elf->e_shnum; i > 0; --i) {
|
noinline size_t uint64toarray_radix8(uint64_t i, char a[hasatleast 24]) {
|
||||||
shdr = getelfsectionheaderaddress(elf, mapsize, i - 1);
|
size_t j;
|
||||||
if ((intptr_t)addr >= shdr->sh_addr &&
|
j = 0;
|
||||||
(intptr_t)addr < shdr->sh_addr + shdr->sh_size) {
|
do {
|
||||||
return shdr;
|
a[j++] = i % 8 + '0';
|
||||||
}
|
i /= 8;
|
||||||
}
|
} while (i > 0);
|
||||||
}
|
a[j] = '\0';
|
||||||
return NULL;
|
reverse(a, j);
|
||||||
|
return j;
|
||||||
}
|
}
|
|
@ -20,10 +20,9 @@ COSMOPOLITAN_C_START_
|
||||||
struct MappedFile;
|
struct MappedFile;
|
||||||
|
|
||||||
Elf64_Ehdr *mapelfread(const char *, struct MappedFile *);
|
Elf64_Ehdr *mapelfread(const char *, struct MappedFile *);
|
||||||
char *getelfstringtable(const Elf64_Ehdr *, size_t);
|
char *GetElfStringTable(const Elf64_Ehdr *, size_t);
|
||||||
Elf64_Sym *getelfsymboltable(const Elf64_Ehdr *, size_t, Elf64_Xword *);
|
Elf64_Sym *GetElfSymbolTable(const Elf64_Ehdr *, size_t, Elf64_Xword *);
|
||||||
Elf64_Shdr *getelfsectionbyaddress(const Elf64_Ehdr *, size_t, void *);
|
bool IsElf64Binary(const Elf64_Ehdr *, size_t);
|
||||||
bool iself64binary(const Elf64_Ehdr *, size_t);
|
|
||||||
|
|
||||||
forceinline void checkelfaddress(const Elf64_Ehdr *elf, size_t mapsize,
|
forceinline void checkelfaddress(const Elf64_Ehdr *elf, size_t mapsize,
|
||||||
intptr_t addr, size_t addrsize) {
|
intptr_t addr, size_t addrsize) {
|
||||||
|
@ -94,7 +93,7 @@ static inline void getelfvirtualaddressrange(const Elf64_Ehdr *elf,
|
||||||
if (out_end) *out_end = end;
|
if (out_end) *out_end = end;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline char *getelfstring(const Elf64_Ehdr *elf, size_t mapsize,
|
static inline char *GetElfString(const Elf64_Ehdr *elf, size_t mapsize,
|
||||||
const char *strtab, Elf64_Word rva) {
|
const char *strtab, Elf64_Word rva) {
|
||||||
intptr_t addr = (intptr_t)strtab + rva;
|
intptr_t addr = (intptr_t)strtab + rva;
|
||||||
#if !(TRUSTWORTHY + ELF_TRUSTWORTHY + 0)
|
#if !(TRUSTWORTHY + ELF_TRUSTWORTHY + 0)
|
||||||
|
@ -105,10 +104,10 @@ static inline char *getelfstring(const Elf64_Ehdr *elf, size_t mapsize,
|
||||||
return (char *)addr;
|
return (char *)addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline const char *getelfsectionname(const Elf64_Ehdr *elf,
|
static inline const char *GetElfSectionName(const Elf64_Ehdr *elf,
|
||||||
size_t mapsize, Elf64_Shdr *shdr) {
|
size_t mapsize, Elf64_Shdr *shdr) {
|
||||||
if (!elf || !shdr) return NULL;
|
if (!elf || !shdr) return NULL;
|
||||||
return getelfstring(elf, mapsize, getelfsectionnamestringtable(elf, mapsize),
|
return GetElfString(elf, mapsize, getelfsectionnamestringtable(elf, mapsize),
|
||||||
shdr->sh_name);
|
shdr->sh_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "libc/elf/def.h"
|
#include "libc/elf/def.h"
|
||||||
#include "libc/elf/elf.h"
|
#include "libc/elf/elf.h"
|
||||||
|
|
||||||
char *getelfstringtable(const Elf64_Ehdr *elf, size_t mapsize) {
|
char *GetElfStringTable(const Elf64_Ehdr *elf, size_t mapsize) {
|
||||||
Elf64_Half i;
|
Elf64_Half i;
|
||||||
Elf64_Shdr *shdr;
|
Elf64_Shdr *shdr;
|
||||||
for (i = elf->e_shnum; i > 0; --i) {
|
for (i = elf->e_shnum; i > 0; --i) {
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "libc/elf/def.h"
|
#include "libc/elf/def.h"
|
||||||
#include "libc/elf/elf.h"
|
#include "libc/elf/elf.h"
|
||||||
|
|
||||||
Elf64_Sym *getelfsymboltable(const Elf64_Ehdr *elf, size_t mapsize,
|
Elf64_Sym *GetElfSymbolTable(const Elf64_Ehdr *elf, size_t mapsize,
|
||||||
Elf64_Xword *out_count) {
|
Elf64_Xword *out_count) {
|
||||||
Elf64_Half i;
|
Elf64_Half i;
|
||||||
Elf64_Shdr *shdr;
|
Elf64_Shdr *shdr;
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/elf/elf.h"
|
#include "libc/elf/elf.h"
|
||||||
|
|
||||||
bool iself64binary(const Elf64_Ehdr *elf, size_t mapsize) {
|
bool IsElf64Binary(const Elf64_Ehdr *elf, size_t mapsize) {
|
||||||
if (mapsize < sizeof(Elf64_Ehdr)) return false;
|
if (mapsize < sizeof(Elf64_Ehdr)) return false;
|
||||||
if (memcmp(elf->e_ident, ELFMAG, 4)) return false;
|
if (memcmp(elf->e_ident, ELFMAG, 4)) return false;
|
||||||
return (elf->e_ident[EI_CLASS] == ELFCLASSNONE ||
|
return (elf->e_ident[EI_CLASS] == ELFCLASSNONE ||
|
||||||
|
|
|
@ -10,6 +10,7 @@ typedef struct Elf64_Sym {
|
||||||
uint8_t st_info;
|
uint8_t st_info;
|
||||||
/* STV_{DEFAULT,INTERNAL,HIDDEN,PROTECTED} */
|
/* STV_{DEFAULT,INTERNAL,HIDDEN,PROTECTED} */
|
||||||
uint8_t st_other;
|
uint8_t st_other;
|
||||||
|
/* SHN_UNDEF, <section index>, SHN_ABS, SHN_COMMON, etc. */
|
||||||
Elf64_Section st_shndx;
|
Elf64_Section st_shndx;
|
||||||
Elf64_Addr st_value;
|
Elf64_Addr st_value;
|
||||||
Elf64_Xword st_size;
|
Elf64_Xword st_size;
|
||||||
|
|
|
@ -63,7 +63,7 @@ int strerror_r(int err, char *buf, size_t size) {
|
||||||
if (FormatMessage(
|
if (FormatMessage(
|
||||||
kNtFormatMessageFromSystem | kNtFormatMessageIgnoreInserts, NULL,
|
kNtFormatMessageFromSystem | kNtFormatMessageIgnoreInserts, NULL,
|
||||||
err, 0, buf16, ARRAYLEN(buf16) - 1, 0) > 0) {
|
err, 0, buf16, ARRAYLEN(buf16) - 1, 0) > 0) {
|
||||||
chomp(buf16);
|
chomp16(buf16);
|
||||||
} else {
|
} else {
|
||||||
buf16[0] = u'\0';
|
buf16[0] = u'\0';
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,6 +152,7 @@ relegated static void ShowMemoryMappings(int outfd) {
|
||||||
|
|
||||||
relegated static void ShowCrashReport(int err, int fd, int sig,
|
relegated static void ShowCrashReport(int err, int fd, int sig,
|
||||||
ucontext_t *ctx) {
|
ucontext_t *ctx) {
|
||||||
|
int i;
|
||||||
struct utsname names;
|
struct utsname names;
|
||||||
(dprintf)(fd, VEIL("r", "\r\n%serror%s: Uncaught SIG%s\r\n %s\r\n %s\r\n"),
|
(dprintf)(fd, VEIL("r", "\r\n%serror%s: Uncaught SIG%s\r\n %s\r\n %s\r\n"),
|
||||||
RED2, RESET, TinyStrSignal(sig), getauxval(AT_EXECFN),
|
RED2, RESET, TinyStrSignal(sig), getauxval(AT_EXECFN),
|
||||||
|
@ -167,6 +168,11 @@ relegated static void ShowCrashReport(int err, int fd, int sig,
|
||||||
}
|
}
|
||||||
write(fd, "\r\n", 2);
|
write(fd, "\r\n", 2);
|
||||||
ShowMemoryMappings(fd);
|
ShowMemoryMappings(fd);
|
||||||
|
write(fd, "\r\n", 2);
|
||||||
|
for (i = 0; i < g_argc; ++i) {
|
||||||
|
write(fd, g_argv[i], strlen(g_argv[i]));
|
||||||
|
write(fd, "\r\n", 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
relegated static void RestoreDefaultCrashSignalHandlers(void) {
|
relegated static void RestoreDefaultCrashSignalHandlers(void) {
|
||||||
|
|
|
@ -186,10 +186,10 @@
|
||||||
.endif
|
.endif
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
/ Overrides LOOP instruction.
|
/ LOOP Instruction Replacement.
|
||||||
/ With its mop-Fusion Mexican equivalent.
|
/ With its mop-Fusion Mexican equivalent.
|
||||||
/ Thus avoiding 3x legacy pipeline slowdown.
|
/ Thus avoiding 3x legacy pipeline slowdown.
|
||||||
.macro loop label:req
|
.macro .loop label:req
|
||||||
.byte 0x83,0xe9,0x01 # sub $1,%ecx
|
.byte 0x83,0xe9,0x01 # sub $1,%ecx
|
||||||
jnz \label
|
jnz \label
|
||||||
.endm
|
.endm
|
||||||
|
|
|
@ -59,7 +59,7 @@ crc32init:
|
||||||
pand %xmm0,%xmm3
|
pand %xmm0,%xmm3
|
||||||
pxor %xmm4,%xmm3
|
pxor %xmm4,%xmm3
|
||||||
movdqa %xmm3,%xmm4
|
movdqa %xmm3,%xmm4
|
||||||
loop 2b
|
.loop 2b
|
||||||
movdqu %xmm3,(%rdi)
|
movdqu %xmm3,(%rdi)
|
||||||
add $16,%rdi
|
add $16,%rdi
|
||||||
paddd %xmm2,%xmm1
|
paddd %xmm2,%xmm1
|
||||||
|
|
|
@ -35,7 +35,7 @@ imapxlatab:
|
||||||
.align 8
|
.align 8
|
||||||
1: stosq
|
1: stosq
|
||||||
add %rdx,%rax
|
add %rdx,%rax
|
||||||
loop 1b
|
.loop 1b
|
||||||
.leafepilogue
|
.leafepilogue
|
||||||
.endfn imapxlatab,globl,hidden
|
.endfn imapxlatab,globl,hidden
|
||||||
.source __FILE__
|
.source __FILE__
|
||||||
|
|
|
@ -35,13 +35,13 @@ kBase36:.zero 256
|
||||||
pushpop 10,%rcx
|
pushpop 10,%rcx
|
||||||
0: inc %eax
|
0: inc %eax
|
||||||
stosb
|
stosb
|
||||||
loop 0b
|
.loop 0b
|
||||||
add $'A-1-'9,%rdi
|
add $'A-1-'9,%rdi
|
||||||
pushpop 'Z+1-'A,%rcx
|
pushpop 'Z+1-'A,%rcx
|
||||||
0: inc %eax
|
0: inc %eax
|
||||||
mov %al,0x20(%rdi)
|
mov %al,0x20(%rdi)
|
||||||
stosb
|
stosb
|
||||||
loop 0b
|
.loop 0b
|
||||||
add $255-'Z,%rdi
|
add $255-'Z,%rdi
|
||||||
.init.end 300,_init_kBase36
|
.init.end 300,_init_kBase36
|
||||||
.source __FILE__
|
.source __FILE__
|
||||||
|
|
|
@ -51,7 +51,7 @@ kToLower16:
|
||||||
mov $256,%ecx
|
mov $256,%ecx
|
||||||
0: lodsb
|
0: lodsb
|
||||||
stosw
|
stosw
|
||||||
loop 0b
|
.loop 0b
|
||||||
pop %rsi
|
pop %rsi
|
||||||
.init.end 300,_init_kToLower
|
.init.end 300,_init_kToLower
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,6 @@ kToUpper:
|
||||||
call imapxlatab
|
call imapxlatab
|
||||||
pushpop 'z-'a,%rcx
|
pushpop 'z-'a,%rcx
|
||||||
0: subb $0x20,(%r8,%rcx)
|
0: subb $0x20,(%r8,%rcx)
|
||||||
loop 0b
|
.loop 0b
|
||||||
.init.end 300,_init_kToUpper
|
.init.end 300,_init_kToUpper
|
||||||
.source __FILE__
|
.source __FILE__
|
||||||
|
|
|
@ -36,7 +36,7 @@ memjmpinit:
|
||||||
lodsb
|
lodsb
|
||||||
add %rdx,%rax
|
add %rdx,%rax
|
||||||
stosq
|
stosq
|
||||||
loop 0b
|
.loop 0b
|
||||||
xor %eax,%eax
|
xor %eax,%eax
|
||||||
testb X86_HAVE(ERMS)+kCpuids(%rip)
|
testb X86_HAVE(ERMS)+kCpuids(%rip)
|
||||||
setnz %al
|
setnz %al
|
||||||
|
|
|
@ -34,7 +34,7 @@ rldecode:
|
||||||
lodsb
|
lodsb
|
||||||
jrcxz 2f
|
jrcxz 2f
|
||||||
1: stosb
|
1: stosb
|
||||||
loop 1b
|
.loop 1b
|
||||||
jmp 0b
|
jmp 0b
|
||||||
2: .leafepilogue
|
2: .leafepilogue
|
||||||
.endfn rldecode,globl
|
.endfn rldecode,globl
|
||||||
|
|
|
@ -1,2 +1,12 @@
|
||||||
.include "o/libc/nt/codegen.inc"
|
.include "o/libc/nt/codegen.inc"
|
||||||
.imp KernelBase,__imp_GetComputerNameExW,GetComputerNameExW,449
|
.imp KernelBase,__imp_GetComputerNameExW,GetComputerNameExW,449
|
||||||
|
|
||||||
|
.text.windows
|
||||||
|
GetComputerNameEx:
|
||||||
|
push %rbp
|
||||||
|
mov %rsp,%rbp
|
||||||
|
.profilable
|
||||||
|
mov __imp_GetComputerNameExW(%rip),%rax
|
||||||
|
jmp __sysv2nt
|
||||||
|
.endfn GetComputerNameEx,globl
|
||||||
|
.previous
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef COSMOPOLITAN_LIBC_NT_ENUM_COMPUTERNAMEFORMAT_H_
|
||||||
|
#define COSMOPOLITAN_LIBC_NT_ENUM_COMPUTERNAMEFORMAT_H_
|
||||||
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
|
||||||
|
#define kNtComputerNameNetBios 0
|
||||||
|
#define kNtComputerNameDnsHostname 1
|
||||||
|
#define kNtComputerNameDnsDomain 2
|
||||||
|
#define kNtComputerNameDnsFullyQualified 3
|
||||||
|
#define kNtComputerNamePhysicalNetBios 4
|
||||||
|
#define kNtComputerNamePhysicalDnsHostname 5
|
||||||
|
#define kNtComputerNamePhysicalDnsDomain 6
|
||||||
|
#define kNtComputerNamePhysicalDnsFullyQualified 7
|
||||||
|
#define kNtComputerName_MAX 8
|
||||||
|
|
||||||
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
#endif /* COSMOPOLITAN_LIBC_NT_ENUM_COMPUTERNAMEFORMAT_H_ */
|
|
@ -1979,7 +1979,7 @@ imp 'GetCompressedFileSizeTransactedA' GetCompressedFileSizeTransactedA kern
|
||||||
imp 'GetCompressedFileSizeTransacted' GetCompressedFileSizeTransactedW kernel32 479
|
imp 'GetCompressedFileSizeTransacted' GetCompressedFileSizeTransactedW kernel32 479
|
||||||
imp 'GetComputerNameA' GetComputerNameA kernel32 481
|
imp 'GetComputerNameA' GetComputerNameA kernel32 481
|
||||||
imp 'GetComputerNameExA' GetComputerNameExA KernelBase 448
|
imp 'GetComputerNameExA' GetComputerNameExA KernelBase 448
|
||||||
imp 'GetComputerNameEx' GetComputerNameExW KernelBase 449
|
imp 'GetComputerNameEx' GetComputerNameExW KernelBase 449 3
|
||||||
imp 'GetComputerName' GetComputerNameW kernel32 484
|
imp 'GetComputerName' GetComputerNameW kernel32 484
|
||||||
imp 'GetConsoleAliasA' GetConsoleAliasA KernelBase 450
|
imp 'GetConsoleAliasA' GetConsoleAliasA KernelBase 450
|
||||||
imp 'GetConsoleAliasExesA' GetConsoleAliasExesA KernelBase 451
|
imp 'GetConsoleAliasExesA' GetConsoleAliasExesA KernelBase 451
|
||||||
|
|
|
@ -46,12 +46,14 @@ int64_t CreateFileMappingNuma(
|
||||||
const struct NtSecurityAttributes *opt_lpFileMappingAttributes,
|
const struct NtSecurityAttributes *opt_lpFileMappingAttributes,
|
||||||
uint32_t flProtect, uint32_t dwMaximumSizeHigh, uint32_t dwMaximumSizeLow,
|
uint32_t flProtect, uint32_t dwMaximumSizeHigh, uint32_t dwMaximumSizeLow,
|
||||||
const char16_t *opt_lpName, uint32_t nndDesiredNumaNode);
|
const char16_t *opt_lpName, uint32_t nndDesiredNumaNode);
|
||||||
|
|
||||||
void *MapViewOfFileExNuma(
|
void *MapViewOfFileExNuma(
|
||||||
int64_t hFileMappingObject, /* @see CreateFileMapping() */
|
int64_t hFileMappingObject, /* @see CreateFileMapping() */
|
||||||
uint32_t dwDesiredAccess, uint32_t dwFileOffsetHigh, /* high order bits */
|
uint32_t dwDesiredAccess, uint32_t dwFileOffsetHigh, /* high order bits */
|
||||||
uint32_t dwFileOffsetLow, /* low order bits */
|
uint32_t dwFileOffsetLow, /* low order bits */
|
||||||
size_t dwNumberOfBytesToMap, void *opt_lpDesiredBaseAddress,
|
size_t dwNumberOfBytesToMap, void *opt_lpDesiredBaseAddress,
|
||||||
uint32_t nndDesiredNumaNode);
|
uint32_t nndDesiredNumaNode);
|
||||||
|
|
||||||
bool32 UnmapViewOfFile(const void *lpBaseAddress);
|
bool32 UnmapViewOfFile(const void *lpBaseAddress);
|
||||||
bool32 FlushViewOfFile(const void *lpBaseAddress,
|
bool32 FlushViewOfFile(const void *lpBaseAddress,
|
||||||
size_t dwNumberOfBytesToFlush);
|
size_t dwNumberOfBytesToFlush);
|
||||||
|
|
|
@ -152,6 +152,8 @@ $(LIBC_NT_NTDLL_A): \
|
||||||
libc/nt/ntdll/ \
|
libc/nt/ntdll/ \
|
||||||
$(LIBC_NT_NTDLL_A).pkg \
|
$(LIBC_NT_NTDLL_A).pkg \
|
||||||
$(LIBC_NT_NTDLL_A_OBJS)
|
$(LIBC_NT_NTDLL_A_OBJS)
|
||||||
|
@$(file >$@.cmd) $(file >>$@.cmd,$(ARCHIVE) $@ $^ >$(LIBC_NT_NTDLL_A).cmd)
|
||||||
|
@$(ARCHIVE) $@ $^
|
||||||
|
|
||||||
$(LIBC_NT_NTDLL_A).pkg: \
|
$(LIBC_NT_NTDLL_A).pkg: \
|
||||||
$(LIBC_NT_NTDLL_A_OBJS) \
|
$(LIBC_NT_NTDLL_A_OBJS) \
|
||||||
|
|
|
@ -13,6 +13,9 @@ uint32_t GetSystemDirectoryA(char *lpBuffer, uint32_t uSize);
|
||||||
uint32_t GetWindowsDirectory(char16_t *lpBuffer, uint32_t uSize);
|
uint32_t GetWindowsDirectory(char16_t *lpBuffer, uint32_t uSize);
|
||||||
uint32_t GetTempPath(uint32_t uSize, char16_t *lpBuffer);
|
uint32_t GetTempPath(uint32_t uSize, char16_t *lpBuffer);
|
||||||
|
|
||||||
|
bool32 GetComputerNameEx(/* enum/computernameformat.h */ int NameType,
|
||||||
|
char16_t *opt_lpBuffer, uint32_t *nSize);
|
||||||
|
|
||||||
#if ShouldUseMsabiAttribute()
|
#if ShouldUseMsabiAttribute()
|
||||||
#include "libc/nt/thunk/systeminfo.inc"
|
#include "libc/nt/thunk/systeminfo.inc"
|
||||||
#endif /* ShouldUseMsabiAttribute() */
|
#endif /* ShouldUseMsabiAttribute() */
|
||||||
|
|
|
@ -38,8 +38,8 @@ static textwindows struct DirectMap DirectMapNt(void *addr, size_t size,
|
||||||
protect = prot2nt(prot, flags);
|
protect = prot2nt(prot, flags);
|
||||||
access = fprot2nt(prot, flags);
|
access = fprot2nt(prot, flags);
|
||||||
if ((res.maphandle =
|
if ((res.maphandle =
|
||||||
CreateFileMappingNuma(handle, &kNtIsInheritable, protect, size >> 32,
|
CreateFileMappingNuma(handle, NULL, protect, size >> 32, size, NULL,
|
||||||
size, NULL, kNtNumaNoPreferredNode))) {
|
kNtNumaNoPreferredNode))) {
|
||||||
if (!(res.addr = MapViewOfFileExNuma(res.maphandle, access, off >> 32, off,
|
if (!(res.addr = MapViewOfFileExNuma(res.maphandle, access, off >> 32, off,
|
||||||
size, addr, kNtNumaNoPreferredNode))) {
|
size, addr, kNtNumaNoPreferredNode))) {
|
||||||
CloseHandle(res.maphandle);
|
CloseHandle(res.maphandle);
|
||||||
|
|
|
@ -42,16 +42,13 @@ _executive:
|
||||||
mov %rdx,%r14
|
mov %rdx,%r14
|
||||||
mov %rcx,%r15
|
mov %rcx,%r15
|
||||||
call _spawn
|
call _spawn
|
||||||
call _getstack
|
mov %r12d,%edi
|
||||||
mov %rax,%rdi
|
mov %r13,%rsi
|
||||||
|
mov %r14,%rdx
|
||||||
|
mov %r15,%rcx
|
||||||
.weak main
|
.weak main
|
||||||
mov $main,%esi
|
call main
|
||||||
mov %r12,%rdx
|
xchg %eax,%edi
|
||||||
mov %r13,%rcx
|
|
||||||
mov %r14,%r8
|
|
||||||
mov %r15,%r9
|
|
||||||
call _setstack
|
|
||||||
mov %eax,%edi
|
|
||||||
call exit
|
call exit
|
||||||
.endfn _executive,weak,hidden
|
.endfn _executive,weak,hidden
|
||||||
ud2
|
ud2
|
||||||
|
|
|
@ -25,6 +25,7 @@ void *__cxa_finalize(void *) hidden;
|
||||||
void _executive(int, char **, char **, long (*)[2]) hidden noreturn;
|
void _executive(int, char **, char **, long (*)[2]) hidden noreturn;
|
||||||
void __stack_chk_fail(void) noreturn relegated;
|
void __stack_chk_fail(void) noreturn relegated;
|
||||||
void __stack_chk_fail_local(void) noreturn relegated hidden;
|
void __stack_chk_fail_local(void) noreturn relegated hidden;
|
||||||
|
long _setstack(void *, void *, ...) hidden;
|
||||||
int GetDosArgv(const char16_t *, char *, size_t, char **, size_t) hidden;
|
int GetDosArgv(const char16_t *, char *, size_t, char **, size_t) hidden;
|
||||||
|
|
||||||
forceinline void AssertNeverCalledWhileTerminating(void) {
|
forceinline void AssertNeverCalledWhileTerminating(void) {
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "libc/runtime/ezmap.h"
|
#include "libc/runtime/ezmap.h"
|
||||||
|
|
||||||
Elf64_Ehdr *mapelfread(const char *filename, struct MappedFile *mf) {
|
Elf64_Ehdr *mapelfread(const char *filename, struct MappedFile *mf) {
|
||||||
if (mapfileread(filename, mf) != -1 && iself64binary(mf->addr, mf->size)) {
|
if (mapfileread(filename, mf) != -1 && IsElf64Binary(mf->addr, mf->size)) {
|
||||||
return mf->addr;
|
return mf->addr;
|
||||||
} else {
|
} else {
|
||||||
unmapfile(mf);
|
unmapfile(mf);
|
||||||
|
|
|
@ -27,7 +27,9 @@
|
||||||
/**
|
/**
|
||||||
* Synchronize memory mapping changes to disk.
|
* Synchronize memory mapping changes to disk.
|
||||||
*
|
*
|
||||||
* @param flags needs MS_SYNC or MS_ASYNC and can have MS_INVALIDATE
|
* Without this, there's no guarantee memory is written back to disk.
|
||||||
|
*
|
||||||
|
* @param flags needs MS_ASYNC or MS_SYNC and can have MS_INVALIDATE
|
||||||
* @return 0 on success or -1 w/ errno
|
* @return 0 on success or -1 w/ errno
|
||||||
*/
|
*/
|
||||||
int msync(void *addr, size_t size, int flags) {
|
int msync(void *addr, size_t size, int flags) {
|
||||||
|
|
|
@ -39,8 +39,8 @@ struct SymbolTable *OpenSymbolTable(const char *filename) {
|
||||||
t = MAP_FAILED;
|
t = MAP_FAILED;
|
||||||
if (filename && (t = mapanon(BIGPAGESIZE)) != MAP_FAILED &&
|
if (filename && (t = mapanon(BIGPAGESIZE)) != MAP_FAILED &&
|
||||||
mapelfread(filename, &t->mf) &&
|
mapelfread(filename, &t->mf) &&
|
||||||
(t->name_base = getelfstringtable(t->elf, t->elfsize)) != NULL &&
|
(t->name_base = GetElfStringTable(t->elf, t->elfsize)) != NULL &&
|
||||||
(symtab = getelfsymboltable(t->elf, t->elfsize, &t->count)) &&
|
(symtab = GetElfSymbolTable(t->elf, t->elfsize, &t->count)) &&
|
||||||
sizeof(struct SymbolTable) + sizeof(struct Symbol) * t->count <
|
sizeof(struct SymbolTable) + sizeof(struct Symbol) * t->count <
|
||||||
(t->scratch = BIGPAGESIZE)) {
|
(t->scratch = BIGPAGESIZE)) {
|
||||||
getelfvirtualaddressrange(t->elf, t->elfsize, &t->addr_base, &t->addr_end);
|
getelfvirtualaddressrange(t->elf, t->elfsize, &t->addr_base, &t->addr_end);
|
||||||
|
|
|
@ -43,7 +43,6 @@ void longjmp(jmp_buf, int) libcesque noreturn paramsnonnull();
|
||||||
void exit(int) noreturn;
|
void exit(int) noreturn;
|
||||||
void _exit(int) libcesque noreturn;
|
void _exit(int) libcesque noreturn;
|
||||||
void _Exit(int) libcesque noreturn;
|
void _Exit(int) libcesque noreturn;
|
||||||
long _setstack(void *, void *, ...);
|
|
||||||
void abort(void) noreturn noinstrument;
|
void abort(void) noreturn noinstrument;
|
||||||
void panic(void) noreturn noinstrument privileged;
|
void panic(void) noreturn noinstrument privileged;
|
||||||
void triplf(void) noreturn noinstrument privileged;
|
void triplf(void) noreturn noinstrument privileged;
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
/ @param rdi is new rsp, passed as malloc(size) + size
|
/ @param rdi is new rsp, passed as malloc(size) + size
|
||||||
/ @param rsi is function to call in new stack space
|
/ @param rsi is function to call in new stack space
|
||||||
/ @param rdx,rcx,r8,r9 get passed as args to rsi
|
/ @param rdx,rcx,r8,r9 get passed as args to rsi
|
||||||
/ @return happens on original stack
|
/ @return rax and happens on original stack
|
||||||
_setstack:
|
_setstack:
|
||||||
push %rbp
|
push %rbp
|
||||||
mov %rsp,%rbp
|
mov %rsp,%rbp
|
||||||
|
@ -43,4 +43,4 @@ _setstack:
|
||||||
pop %rbx
|
pop %rbx
|
||||||
pop %rbp
|
pop %rbp
|
||||||
ret
|
ret
|
||||||
.endfn _setstack,globl
|
.endfn _setstack,globl,hidden
|
||||||
|
|
|
@ -25,7 +25,9 @@
|
||||||
#include "libc/nt/enum/consolemodeflags.h"
|
#include "libc/nt/enum/consolemodeflags.h"
|
||||||
#include "libc/nt/enum/filetype.h"
|
#include "libc/nt/enum/filetype.h"
|
||||||
#include "libc/nt/enum/loadlibrarysearch.h"
|
#include "libc/nt/enum/loadlibrarysearch.h"
|
||||||
|
#include "libc/nt/enum/pageflags.h"
|
||||||
#include "libc/nt/files.h"
|
#include "libc/nt/files.h"
|
||||||
|
#include "libc/nt/memory.h"
|
||||||
#include "libc/nt/pedef.h"
|
#include "libc/nt/pedef.h"
|
||||||
#include "libc/nt/process.h"
|
#include "libc/nt/process.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
|
@ -117,10 +119,10 @@ static textwindows void NormalizeCmdExe(void) {
|
||||||
* 3. Environment variables are passed to us as a sorted UTF-16 double
|
* 3. Environment variables are passed to us as a sorted UTF-16 double
|
||||||
* NUL terminated list. We translate this to char ** using UTF-8.
|
* NUL terminated list. We translate this to char ** using UTF-8.
|
||||||
*
|
*
|
||||||
* 4. NT likes to choose a stack address that's beneath the program
|
* 4. Allocates new stack at a high address. NT likes to choose a
|
||||||
* image. We want to be able to assume that stack addresses are
|
* stack address that's beneath the program image. We want to be
|
||||||
* located at higher addresses than heap and program memory. So the
|
* able to assume that stack addresses are located at higher
|
||||||
* _executive() function will switch stacks appropriately.
|
* addresses than heap and program memory.
|
||||||
*
|
*
|
||||||
* 5. Windows users are afraid of "drive-by downloads" where someone
|
* 5. Windows users are afraid of "drive-by downloads" where someone
|
||||||
* might accidentally an evil DLL to their Downloads folder which
|
* might accidentally an evil DLL to their Downloads folder which
|
||||||
|
@ -131,21 +133,27 @@ static textwindows void NormalizeCmdExe(void) {
|
||||||
*/
|
*/
|
||||||
textwindows int WinMain(void *hInstance, void *hPrevInstance,
|
textwindows int WinMain(void *hInstance, void *hPrevInstance,
|
||||||
const char *lpCmdLine, int nCmdShow) {
|
const char *lpCmdLine, int nCmdShow) {
|
||||||
|
char *stack;
|
||||||
int i, count;
|
int i, count;
|
||||||
const char16_t *cmd16, *env16;
|
const char16_t *cmd16, *env16;
|
||||||
char *argarray[512], *envarray[512];
|
char *argv[512], *envp[512];
|
||||||
char argblock[ARG_MAX], envblock[ENV_MAX];
|
char argblock[ARG_MAX], envblock[ENV_MAX];
|
||||||
long auxarray[][2] = {{pushpop(0L), pushpop(0L)}};
|
long auxv[][2] = {{pushpop(0L), pushpop(0L)}};
|
||||||
MitigateDriveByDownloads();
|
MitigateDriveByDownloads();
|
||||||
NormalizeCmdExe();
|
NormalizeCmdExe();
|
||||||
*(/*unconst*/ int *)&hostos = WINDOWS;
|
*(/*unconst*/ int *)&hostos = WINDOWS;
|
||||||
cmd16 = GetCommandLine();
|
cmd16 = GetCommandLine();
|
||||||
env16 = GetEnvironmentStrings();
|
env16 = GetEnvironmentStrings();
|
||||||
count = GetDosArgv(cmd16, argblock, ARG_MAX, argarray, 512);
|
count = GetDosArgv(cmd16, argblock, ARG_MAX, argv, 512);
|
||||||
for (i = 0; argarray[0][i]; ++i) {
|
for (i = 0; argv[0][i]; ++i) {
|
||||||
if (argarray[0][i] == '\\') argarray[0][i] = '/';
|
if (argv[0][i] == '\\') argv[0][i] = '/';
|
||||||
}
|
}
|
||||||
GetDosEnviron(env16, envblock, ENV_MAX, envarray, 512);
|
GetDosEnviron(env16, envblock, ENV_MAX, envp, 512);
|
||||||
FreeEnvironmentStrings(env16);
|
FreeEnvironmentStrings(env16);
|
||||||
_executive(count, argarray, envarray, auxarray);
|
stack = MapViewOfFileExNuma(
|
||||||
|
CreateFileMappingNuma(-1, NULL, pushpop(kNtPageReadwrite), 0, STACKSIZE,
|
||||||
|
NULL, kNtNumaNoPreferredNode),
|
||||||
|
kNtFileMapRead | kNtFileMapWrite, 0, 0, STACKSIZE,
|
||||||
|
(char *)0x777000000000 - STACKSIZE, kNtNumaNoPreferredNode);
|
||||||
|
return _setstack(stack + STACKSIZE, _executive, count, argv, envp, auxv);
|
||||||
}
|
}
|
||||||
|
|
|
@ -256,97 +256,6 @@ bool luhn(const char *);
|
||||||
|
|
||||||
char *strsignal(int) returnsnonnull libcesque;
|
char *strsignal(int) returnsnonnull libcesque;
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
|
||||||
│ cosmopolitan § strings » hooks ─╬─│┼
|
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
|
||||||
|
|
||||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
|
||||||
extern int (*const hook$strcmp16)(const char16_t *, const char16_t *);
|
|
||||||
extern int (*const hook$strncmp16)(const char16_t *, const char16_t *, size_t);
|
|
||||||
extern int (*const hook$wcscmp)(const wchar_t *, const wchar_t *);
|
|
||||||
extern int (*const hook$wcsncmp)(const wchar_t *, const wchar_t *, size_t);
|
|
||||||
#define __STR_HOOK(SYMBOL) hook$##SYMBOL
|
|
||||||
#else
|
|
||||||
#define __STR_HOOK(SYMBOL) SYMBOL
|
|
||||||
#endif /* GNUC && !ANSI */
|
|
||||||
|
|
||||||
/* TODO(jart): Use @gotpcrel. */
|
|
||||||
#undef __STR_HOOK
|
|
||||||
#define __STR_HOOK(SYMBOL) SYMBOL
|
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
|
||||||
│ cosmopolitan § strings » generic typing ─╬─│┼
|
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
|
||||||
|
|
||||||
#if __STDC_VERSION__ + 0 >= 201112
|
|
||||||
|
|
||||||
#define strnlen(s, n) \
|
|
||||||
_Generic(*(s), wchar_t \
|
|
||||||
: wcsnlen, char16_t \
|
|
||||||
: strnlen16, default \
|
|
||||||
: strnlen)(s, n)
|
|
||||||
|
|
||||||
#define strnlen_s(s, n) \
|
|
||||||
_Generic(*(s), wchar_t \
|
|
||||||
: wcsnlen_s, char16_t \
|
|
||||||
: strnlen16_s, default \
|
|
||||||
: strnlen_s)(s, n)
|
|
||||||
|
|
||||||
#define strpbrk(s, c) \
|
|
||||||
_Generic(*(s), wchar_t \
|
|
||||||
: wcspbrk, char16_t \
|
|
||||||
: strpbrk16, default \
|
|
||||||
: strpbrk)(s, c)
|
|
||||||
|
|
||||||
#define strspn(s, c) \
|
|
||||||
_Generic(*(s), wchar_t : wcsspn, char16_t : strspn16, default : strspn)(s, c)
|
|
||||||
|
|
||||||
#define strcspn(s, c) \
|
|
||||||
_Generic(*(s), wchar_t \
|
|
||||||
: wcscspn, char16_t \
|
|
||||||
: strcspn16, default \
|
|
||||||
: strcspn)(s, c)
|
|
||||||
|
|
||||||
/* clang-format off */
|
|
||||||
#define strcmp(s1, s2) \
|
|
||||||
_Generic((s1)[0], \
|
|
||||||
wchar_t: __STR_HOOK(wcscmp), \
|
|
||||||
char16_t: _Generic(*(s2), \
|
|
||||||
char: strcmp16to8, \
|
|
||||||
default: __STR_HOOK(strcmp16)), \
|
|
||||||
default: _Generic(*(s2), \
|
|
||||||
char16_t: strcmp8to16, \
|
|
||||||
default: strcmp))(s1, s2)
|
|
||||||
/* clang-format on */
|
|
||||||
|
|
||||||
#define strncmp(s1, s2, n) \
|
|
||||||
_Generic(*(s1), wchar_t \
|
|
||||||
: __STR_HOOK(wcsncmp), char16_t \
|
|
||||||
: _Generic(*(s2), char \
|
|
||||||
: strncmp16to8, default \
|
|
||||||
: __STR_HOOK(strncmp16)), \
|
|
||||||
default \
|
|
||||||
: _Generic(*(s2), char16_t \
|
|
||||||
: strncmp8to16, default \
|
|
||||||
: strncmp))(s1, s2, n)
|
|
||||||
|
|
||||||
#define strcasecmp(s1, s2) \
|
|
||||||
_Generic(*(s1), wchar_t \
|
|
||||||
: wcscasecmp, char16_t \
|
|
||||||
: strcasecmp16, default \
|
|
||||||
: strcasecmp)(s1, s2)
|
|
||||||
|
|
||||||
#define strncasecmp(s1, s2, n) \
|
|
||||||
_Generic(*(s1), wchar_t \
|
|
||||||
: wcsncasecmp, char16_t \
|
|
||||||
: strncasecmp16, default \
|
|
||||||
: strncasecmp)(s1, s2, n)
|
|
||||||
|
|
||||||
#define chomp(s) \
|
|
||||||
_Generic(*(s), wchar_t : wchomp, char16_t : chomp16, default : chomp)(s)
|
|
||||||
|
|
||||||
#endif /* C11 */
|
|
||||||
|
|
||||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||||
│ cosmopolitan § strings » optimizations ─╬─│┼
|
│ cosmopolitan § strings » optimizations ─╬─│┼
|
||||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
* @see strspn(), strtok_r()
|
* @see strspn(), strtok_r()
|
||||||
* @asyncsignalsafe
|
* @asyncsignalsafe
|
||||||
*/
|
*/
|
||||||
size_t(strcspn)(const char *s, const char *reject) {
|
size_t strcspn(const char *s, const char *reject) {
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; s[i]; ++i) {
|
for (i = 0; s[i]; ++i) {
|
||||||
if (HasCharacter(s[i], reject)) {
|
if (HasCharacter(s[i], reject)) {
|
||||||
|
|
|
@ -20,9 +20,20 @@
|
||||||
#include "libc/nexgen32e/hascharacter.h"
|
#include "libc/nexgen32e/hascharacter.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
#undef strcspn
|
/**
|
||||||
#define char char16_t
|
* Returns prefix length, consisting of chars not in reject.
|
||||||
#define HasCharacter HasCharacter16
|
* a.k.a. Return index of first byte that's in charset.
|
||||||
#define strcspn strcspn16
|
*
|
||||||
|
* @param reject is nul-terminated character set
|
||||||
#include "libc/str/strcspn.c"
|
* @see strspn(), strtok_r()
|
||||||
|
* @asyncsignalsafe
|
||||||
|
*/
|
||||||
|
size_t strcspn16(const char16_t *s, const char16_t *reject) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; s[i]; ++i) {
|
||||||
|
if (HasCharacter16(s[i], reject)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
|
@ -20,9 +20,20 @@
|
||||||
#include "libc/nexgen32e/hascharacter.h"
|
#include "libc/nexgen32e/hascharacter.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
#undef strcspn
|
/**
|
||||||
#define char wchar_t
|
* Returns prefix length, consisting of chars not in reject.
|
||||||
#define HasCharacter HasCharacterWide
|
* a.k.a. Return index of first byte that's in charset.
|
||||||
#define strcspn wcscspn
|
*
|
||||||
|
* @param reject is nul-terminated character set
|
||||||
#include "libc/str/strcspn.c"
|
* @see strspn(), strtok_r()
|
||||||
|
* @asyncsignalsafe
|
||||||
|
*/
|
||||||
|
size_t wcscspn(const wchar_t *s, const wchar_t *reject) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; s[i]; ++i) {
|
||||||
|
if (HasCharacterWide(s[i], reject)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
.include "o/libc/sysv/macros.inc"
|
|
||||||
.scall gethostname 0xffff0057ffffffff globl
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
.include "o/libc/sysv/macros.inc"
|
||||||
|
.scall sync$sysv 0x00240024202400a2 globl hidden
|
|
@ -1,2 +0,0 @@
|
||||||
.include "o/libc/sysv/macros.inc"
|
|
||||||
.scall sync 0x00240024202400a2 globl
|
|
|
@ -178,7 +178,7 @@ scall mlockall 0x010f014421440097 globl
|
||||||
scall munlockall 0x0110014521450098 globl
|
scall munlockall 0x0110014521450098 globl
|
||||||
scall 'setrlimit$sysv' 0x00c300c320c300a0 globl hidden
|
scall 'setrlimit$sysv' 0x00c300c320c300a0 globl hidden
|
||||||
scall chroot 0x003d003d203d00a1 globl
|
scall chroot 0x003d003d203d00a1 globl
|
||||||
scall sync 0x00240024202400a2 globl
|
scall 'sync$sysv' 0x00240024202400a2 globl hidden
|
||||||
scall acct 0x00330033203300a3 globl
|
scall acct 0x00330033203300a3 globl
|
||||||
scall settimeofday 0x0044007a207a00a4 globl
|
scall settimeofday 0x0044007a207a00a4 globl
|
||||||
scall mount 0x0015001520a700a5 globl
|
scall mount 0x0015001520a700a5 globl
|
||||||
|
@ -649,10 +649,10 @@ scall fhlinkat 0xffff0236ffffffff globl
|
||||||
scall fhreadlink 0xffff0237ffffffff globl
|
scall fhreadlink 0xffff0237ffffffff globl
|
||||||
scall getaudit 0xffff01c1ffffffff globl
|
scall getaudit 0xffff01c1ffffffff globl
|
||||||
scall getcontext 0xffff01a5ffffffff globl
|
scall getcontext 0xffff01a5ffffffff globl
|
||||||
scall getdomainname 0xffff00a2ffffffff globl
|
#scall getdomainname 0xffff00a2ffffffff globl
|
||||||
scall getfhat 0xffff0234ffffffff globl
|
scall getfhat 0xffff0234ffffffff globl
|
||||||
scall gethostid 0xffff008effffffff globl
|
scall gethostid 0xffff008effffffff globl
|
||||||
scall gethostname 0xffff0057ffffffff globl
|
#scall gethostname 0xffff0057ffffffff globl
|
||||||
scall getkerninfo 0xffff003fffffffff globl
|
scall getkerninfo 0xffff003fffffffff globl
|
||||||
scall getloginclass 0xffff020bffffffff globl
|
scall getloginclass 0xffff020bffffffff globl
|
||||||
scall 'getpagesize$freebsd' 0xffff0040ffffffff globl hidden
|
scall 'getpagesize$freebsd' 0xffff0040ffffffff globl hidden
|
||||||
|
|
|
@ -0,0 +1,255 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=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 │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/alg/arraylist2.h"
|
||||||
|
#include "libc/bits/bits.h"
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/struct/iovec.h"
|
||||||
|
#include "libc/calls/struct/stat.h"
|
||||||
|
#include "libc/conv/conv.h"
|
||||||
|
#include "libc/conv/itoa.h"
|
||||||
|
#include "libc/elf/def.h"
|
||||||
|
#include "libc/elf/elf.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
|
#include "libc/log/check.h"
|
||||||
|
#include "libc/macros.h"
|
||||||
|
#include "libc/sock/sock.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/sysv/consts/madv.h"
|
||||||
|
#include "libc/sysv/consts/map.h"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
|
#include "libc/sysv/consts/prot.h"
|
||||||
|
#include "libc/x/x.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fileoverview System Five Static Archive Builder.
|
||||||
|
*
|
||||||
|
* GNU ar has a bug which causes it to take hundreds of milliseconds to
|
||||||
|
* build archives like ntdll.a and several minutes for cosmopolitan.a.
|
||||||
|
* This goes quadratically faster taking 1ms to do ntdll w/ hot cache.
|
||||||
|
*
|
||||||
|
* Compared to LLVM ar this tool goes 10x faster because it uses madvise
|
||||||
|
* and copy_file_range which give us the optimal page cached file system
|
||||||
|
* beahvior that a build environment needs.
|
||||||
|
*
|
||||||
|
* This tool also adds a feature: it ignores directory parameters. This
|
||||||
|
* is important because good Makefiles on Linux will generally have the
|
||||||
|
* directory be a .a prerequisite so archives rebuild on file deletion.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct String {
|
||||||
|
size_t i, n;
|
||||||
|
char *p;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Ints {
|
||||||
|
size_t i, n;
|
||||||
|
int *p;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Header {
|
||||||
|
char name[16];
|
||||||
|
char date[12];
|
||||||
|
char uid[6];
|
||||||
|
char gid[6];
|
||||||
|
char mode[8];
|
||||||
|
char size[10];
|
||||||
|
char fmag[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
static void MakeHeader(struct Header *h, const char *name, int ref, int mode,
|
||||||
|
int size) {
|
||||||
|
size_t n;
|
||||||
|
char buf[21];
|
||||||
|
memset(h, ' ', sizeof(*h));
|
||||||
|
n = strlen(name);
|
||||||
|
memcpy(h->name, name, n);
|
||||||
|
if (ref != -1) {
|
||||||
|
memcpy(h->name + n, buf, uint64toarray_radix10(ref, buf));
|
||||||
|
}
|
||||||
|
if (strcmp(name, "//") != 0) {
|
||||||
|
h->date[0] = '0';
|
||||||
|
h->uid[0] = '0';
|
||||||
|
h->gid[0] = '0';
|
||||||
|
memcpy(h->mode, buf, uint64toarray_radix8(mode & 0777, buf));
|
||||||
|
}
|
||||||
|
h->fmag[0] = '`';
|
||||||
|
h->fmag[1] = '\n';
|
||||||
|
memcpy(h->size, buf, uint64toarray_radix10(size, buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
void *elf;
|
||||||
|
char *strs;
|
||||||
|
ssize_t rc;
|
||||||
|
struct stat *st;
|
||||||
|
uint32_t outpos;
|
||||||
|
Elf64_Sym *syms;
|
||||||
|
uint64_t outsize;
|
||||||
|
char **objectargs;
|
||||||
|
uint8_t *tablebuf;
|
||||||
|
struct iovec iov[7];
|
||||||
|
const char *symname;
|
||||||
|
Elf64_Xword symcount;
|
||||||
|
struct Ints symnames;
|
||||||
|
struct String symbols;
|
||||||
|
struct String filenames;
|
||||||
|
const char *options, *outpath;
|
||||||
|
struct Header *header1, *header2;
|
||||||
|
size_t wrote, remain, objectargcount;
|
||||||
|
int *offsets, *modes, *sizes, *names;
|
||||||
|
int i, j, fd, err, name, outfd, tablebufsize;
|
||||||
|
|
||||||
|
st = xmalloc(sizeof(struct stat));
|
||||||
|
symbols.i = 0;
|
||||||
|
symbols.n = 4096;
|
||||||
|
symbols.p = xmalloc(symbols.n);
|
||||||
|
filenames.i = 0;
|
||||||
|
filenames.n = 1024;
|
||||||
|
filenames.p = xmalloc(filenames.n);
|
||||||
|
symnames.i = 0;
|
||||||
|
symnames.n = 1024;
|
||||||
|
symnames.p = xmalloc(symnames.n * sizeof(int));
|
||||||
|
|
||||||
|
CHECK_GT(argc, 3);
|
||||||
|
options = argv[1];
|
||||||
|
outpath = argv[2];
|
||||||
|
objectargs = argv + 3;
|
||||||
|
objectargcount = argc - 3;
|
||||||
|
CHECK_EQ(0, strcmp(options, "rcsD"));
|
||||||
|
modes = xmalloc(sizeof(int) * objectargcount);
|
||||||
|
names = xmalloc(sizeof(int) * objectargcount);
|
||||||
|
sizes = xmalloc(sizeof(int) * objectargcount);
|
||||||
|
|
||||||
|
// load global symbols and populate page cache
|
||||||
|
for (i = 0; i < objectargcount; ++i) {
|
||||||
|
TryAgain:
|
||||||
|
CHECK_NE(-1, (fd = open(objectargs[i], O_RDONLY)));
|
||||||
|
CHECK_NE(-1, fstat(fd, st));
|
||||||
|
CHECK_LT(st->st_size, 0x7ffff000);
|
||||||
|
if (!st->st_size || S_ISDIR(st->st_mode) ||
|
||||||
|
endswith(objectargs[i], ".pkg")) {
|
||||||
|
close(fd);
|
||||||
|
for (j = i; j + 1 < objectargcount; ++j) {
|
||||||
|
objectargs[j] = objectargs[j + 1];
|
||||||
|
}
|
||||||
|
--objectargcount;
|
||||||
|
goto TryAgain;
|
||||||
|
}
|
||||||
|
names[i] = filenames.i;
|
||||||
|
sizes[i] = st->st_size;
|
||||||
|
modes[i] = st->st_mode;
|
||||||
|
CONCAT(&filenames.p, &filenames.i, &filenames.n, basename(objectargs[i]),
|
||||||
|
strlen(basename(objectargs[i])));
|
||||||
|
CONCAT(&filenames.p, &filenames.i, &filenames.n, "/\n", 2);
|
||||||
|
CHECK_NE(MAP_FAILED,
|
||||||
|
(elf = mmap(NULL, st->st_size, PROT_READ, MAP_PRIVATE, fd, 0)));
|
||||||
|
madvise(elf, st->st_size, MADV_WILLNEED);
|
||||||
|
CHECK(IsElf64Binary(elf, st->st_size));
|
||||||
|
CHECK_NOTNULL((strs = GetElfStringTable(elf, st->st_size)));
|
||||||
|
CHECK_NOTNULL((syms = GetElfSymbolTable(elf, st->st_size, &symcount)));
|
||||||
|
for (j = 0; j < symcount; ++j) {
|
||||||
|
if (syms[j].st_shndx == SHN_UNDEF) continue;
|
||||||
|
if (syms[j].st_other == STV_INTERNAL) continue;
|
||||||
|
if (ELF64_ST_BIND(syms[j].st_info) == STB_LOCAL) continue;
|
||||||
|
symname = GetElfString(elf, st->st_size, strs, syms[j].st_name);
|
||||||
|
CONCAT(&symbols.p, &symbols.i, &symbols.n, symname, strlen(symname) + 1);
|
||||||
|
APPEND(&symnames.p, &symnames.i, &symnames.n, &i);
|
||||||
|
}
|
||||||
|
CHECK_NE(-1, munmap(elf, st->st_size));
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
APPEND(&filenames.p, &filenames.i, &filenames.n, "\n");
|
||||||
|
|
||||||
|
// compute length of output archive
|
||||||
|
outsize = 0;
|
||||||
|
tablebufsize = 4 + symnames.i * 4;
|
||||||
|
tablebuf = xmalloc(tablebufsize);
|
||||||
|
offsets = xmalloc(objectargcount * 4);
|
||||||
|
header1 = xmalloc(sizeof(struct Header));
|
||||||
|
header2 = xmalloc(sizeof(struct Header));
|
||||||
|
iov[0].iov_base = "!<arch>\n";
|
||||||
|
outsize += (iov[0].iov_len = 8);
|
||||||
|
iov[1].iov_base = header1;
|
||||||
|
outsize += (iov[1].iov_len = 60);
|
||||||
|
iov[2].iov_base = tablebuf;
|
||||||
|
outsize += (iov[2].iov_len = tablebufsize);
|
||||||
|
iov[3].iov_base = symbols.p;
|
||||||
|
outsize += (iov[3].iov_len = symbols.i);
|
||||||
|
iov[4].iov_base = "\n";
|
||||||
|
outsize += (iov[4].iov_len = outsize & 1);
|
||||||
|
iov[5].iov_base = header2;
|
||||||
|
outsize += (iov[5].iov_len = 60);
|
||||||
|
iov[6].iov_base = filenames.p;
|
||||||
|
outsize += (iov[6].iov_len = filenames.i);
|
||||||
|
for (i = 0; i < objectargcount; ++i) {
|
||||||
|
outsize += outsize & 1;
|
||||||
|
offsets[i] = outsize;
|
||||||
|
outsize += 60;
|
||||||
|
outsize += sizes[i];
|
||||||
|
}
|
||||||
|
CHECK_LE(outsize, 0x7ffff000);
|
||||||
|
|
||||||
|
// serialize metadata
|
||||||
|
MakeHeader(header1, "/", -1, 0, tablebufsize + symbols.i);
|
||||||
|
MakeHeader(header2, "//", -1, 0, filenames.i);
|
||||||
|
WRITE32BE(tablebuf, symnames.i);
|
||||||
|
for (i = 0; i < symnames.i; ++i) {
|
||||||
|
WRITE32BE(tablebuf + 4 + i * 4, offsets[symnames.p[i]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write output archive
|
||||||
|
CHECK_NE(-1, (outfd = open(outpath, O_WRONLY | O_TRUNC | O_CREAT, 0644)));
|
||||||
|
ftruncate(outfd, outsize);
|
||||||
|
if ((outsize = writev(outfd, iov, ARRAYLEN(iov))) == -1) goto fail;
|
||||||
|
for (i = 0; i < objectargcount; ++i) {
|
||||||
|
if ((fd = open(objectargs[i], O_RDONLY)) == -1) goto fail;
|
||||||
|
iov[0].iov_base = "\n";
|
||||||
|
outsize += (iov[0].iov_len = outsize & 1);
|
||||||
|
iov[1].iov_base = header1;
|
||||||
|
outsize += (iov[1].iov_len = 60);
|
||||||
|
MakeHeader(header1, "/", names[i], modes[i], sizes[i]);
|
||||||
|
if (writev(outfd, iov, 2) == -1) goto fail;
|
||||||
|
outsize += (remain = sizes[i]);
|
||||||
|
if (copy_file_range(fd, NULL, outfd, NULL, remain, 0) != remain) goto fail;
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
close(outfd);
|
||||||
|
|
||||||
|
free(header2);
|
||||||
|
free(header1);
|
||||||
|
free(offsets);
|
||||||
|
free(tablebuf);
|
||||||
|
free(sizes);
|
||||||
|
free(names);
|
||||||
|
free(modes);
|
||||||
|
free(symbols.p);
|
||||||
|
free(filenames.p);
|
||||||
|
free(symnames.p);
|
||||||
|
free(st);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
err = errno;
|
||||||
|
if (!err) err = 1;
|
||||||
|
unlink(outpath);
|
||||||
|
fputs("error: ar failed\n", stderr);
|
||||||
|
return err;
|
||||||
|
}
|
|
@ -21,6 +21,7 @@
|
||||||
#include "dsp/tty/tty.h"
|
#include "dsp/tty/tty.h"
|
||||||
#include "libc/alg/arraylist2.h"
|
#include "libc/alg/arraylist2.h"
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
|
#include "libc/bits/bits.h"
|
||||||
#include "libc/bits/safemacros.h"
|
#include "libc/bits/safemacros.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/ioctl.h"
|
#include "libc/calls/ioctl.h"
|
||||||
|
@ -165,7 +166,7 @@ FEATURES\n\
|
||||||
|
|
||||||
struct MemoryView {
|
struct MemoryView {
|
||||||
int64_t start;
|
int64_t start;
|
||||||
unsigned zoom;
|
int zoom;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MachineState {
|
struct MachineState {
|
||||||
|
@ -1158,10 +1159,17 @@ static void ScrollMemoryView(struct Panel *p, struct MemoryView *v, int64_t a) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ZoomMemoryView(struct MemoryView *v, int dy) {
|
static void ZoomMemoryView(struct MemoryView *v, long y, long x, int dy) {
|
||||||
v->start *= (DUMPWIDTH * (1ull << v->zoom));
|
long a, b, i, s;
|
||||||
v->zoom = MIN(MAXZOOM, MAX(0, v->zoom + dy));
|
s = v->start;
|
||||||
v->start /= (DUMPWIDTH * (1ull << v->zoom));
|
a = v->zoom;
|
||||||
|
b = MIN(MAXZOOM, MAX(0, a + dy));
|
||||||
|
i = y * DUMPWIDTH - x;
|
||||||
|
s *= DUMPWIDTH * (1L << a);
|
||||||
|
s += i * (1L << a) - i * (1L << b);
|
||||||
|
s /= DUMPWIDTH * (1L << b);
|
||||||
|
v->zoom = b;
|
||||||
|
v->start = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ScrollMemoryViews(void) {
|
static void ScrollMemoryViews(void) {
|
||||||
|
@ -1171,15 +1179,15 @@ static void ScrollMemoryViews(void) {
|
||||||
ScrollMemoryView(&pan.stack, &stackview, GetSp());
|
ScrollMemoryView(&pan.stack, &stackview, GetSp());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ZoomMemoryViews(struct Panel *p, int dy) {
|
static void ZoomMemoryViews(struct Panel *p, int y, int x, int dy) {
|
||||||
if (p == &pan.code) {
|
if (p == &pan.code) {
|
||||||
ZoomMemoryView(&codeview, dy);
|
ZoomMemoryView(&codeview, y, x, dy);
|
||||||
} else if (p == &pan.readdata) {
|
} else if (p == &pan.readdata) {
|
||||||
ZoomMemoryView(&readview, dy);
|
ZoomMemoryView(&readview, y, x, dy);
|
||||||
} else if (p == &pan.writedata) {
|
} else if (p == &pan.writedata) {
|
||||||
ZoomMemoryView(&writeview, dy);
|
ZoomMemoryView(&writeview, y, x, dy);
|
||||||
} else if (p == &pan.stack) {
|
} else if (p == &pan.stack) {
|
||||||
ZoomMemoryView(&stackview, dy);
|
ZoomMemoryView(&stackview, y, x, dy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1798,14 +1806,18 @@ static void OnDiskServiceGetParams(void) {
|
||||||
static void OnDiskServiceReadSectors(void) {
|
static void OnDiskServiceReadSectors(void) {
|
||||||
static int x;
|
static int x;
|
||||||
uint64_t addr, size;
|
uint64_t addr, size;
|
||||||
int64_t drive, head, track, sector, offset;
|
int64_t sectors, drive, head, track, sector, offset;
|
||||||
|
sectors = m->ax[0];
|
||||||
drive = m->dx[0];
|
drive = m->dx[0];
|
||||||
head = m->dx[1];
|
head = m->dx[1];
|
||||||
track = (m->cx[0] & 0b11000000) << 2 | m->cx[1];
|
track = (m->cx[0] & 0b11000000) << 2 | m->cx[1];
|
||||||
sector = (m->cx[0] & 0b00111111) - 1;
|
sector = (m->cx[0] & 0b00111111) - 1;
|
||||||
offset = head * track * sector * 512;
|
offset = head * track * sector * 512;
|
||||||
size = m->ax[0] * 512;
|
size = sectors * 512;
|
||||||
offset = sector * 512 + track * 512 * 63 + head * 512 * 63 * 1024;
|
offset = sector * 512 + track * 512 * 63 + head * 512 * 63 * 1024;
|
||||||
|
VERBOSEF("bios read sectors %d "
|
||||||
|
"@ sector %ld track %ld head %ld drive %ld offset %#lx",
|
||||||
|
sectors, sector, track, head, drive, offset);
|
||||||
if (0 <= sector && offset + size <= elf->mapsize) {
|
if (0 <= sector && offset + size <= elf->mapsize) {
|
||||||
addr = Read64(m->es) + Read16(m->bx);
|
addr = Read64(m->es) + Read16(m->bx);
|
||||||
if (addr + size <= m->real.n) {
|
if (addr + size <= m->real.n) {
|
||||||
|
@ -1819,6 +1831,8 @@ static void OnDiskServiceReadSectors(void) {
|
||||||
SetCarry(true);
|
SetCarry(true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
WARNF("bios read sector failed 0 <= %d && %lx + %lx <= %lx", sector, offset,
|
||||||
|
size, elf->mapsize);
|
||||||
m->ax[0] = 0x00;
|
m->ax[0] = 0x00;
|
||||||
m->ax[1] = 0x0d;
|
m->ax[1] = 0x0d;
|
||||||
SetCarry(true);
|
SetCarry(true);
|
||||||
|
@ -2074,7 +2088,9 @@ static void OnBinbase(struct Machine *m) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnLongBranch(struct Machine *m) {
|
static void OnLongBranch(struct Machine *m) {
|
||||||
|
if (tuimode) {
|
||||||
Disassemble();
|
Disassemble();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnPageUp(void) {
|
static void OnPageUp(void) {
|
||||||
|
@ -2098,20 +2114,28 @@ static void SetStatus(const char *fmt, ...) {
|
||||||
setitimer(ITIMER_REAL, &((struct itimerval){{0, 0}, {1, 0}}), NULL);
|
setitimer(ITIMER_REAL, &((struct itimerval){{0, 0}, {1, 0}}), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ClampSpeed(int s) {
|
||||||
|
return MAX(-0x1000, MIN(0x40000000, s));
|
||||||
|
}
|
||||||
|
|
||||||
static void OnTurbo(void) {
|
static void OnTurbo(void) {
|
||||||
if (speed >= -1) {
|
if (!speed || speed == -1) {
|
||||||
speed = MIN(0x40000000, MAX(1, speed) << 1); // 1..40mips skip
|
speed = 1;
|
||||||
|
} else if (speed > 0) {
|
||||||
|
speed = ClampSpeed(speed << 1);
|
||||||
} else {
|
} else {
|
||||||
speed >>= 1;
|
speed = ClampSpeed(speed >> 1);
|
||||||
}
|
}
|
||||||
SetStatus("speed %,d", speed);
|
SetStatus("speed %,d", speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnSlowmo(void) {
|
static void OnSlowmo(void) {
|
||||||
if (speed > 0) {
|
if (!speed || speed == 1) {
|
||||||
speed >>= 1;
|
speed = -1;
|
||||||
|
} else if (speed > 0) {
|
||||||
|
speed = ClampSpeed(speed >> 1);
|
||||||
} else {
|
} else {
|
||||||
speed = MAX(-(5 * 1000), MIN(-1, speed) << 1); // 1ms..5s delay
|
speed = ClampSpeed(speed << 1);
|
||||||
}
|
}
|
||||||
SetStatus("speed %,d", speed);
|
SetStatus("speed %,d", speed);
|
||||||
}
|
}
|
||||||
|
@ -2221,7 +2245,7 @@ static void Sleep(int ms) {
|
||||||
poll((struct pollfd[]){{ttyin, POLLIN}}, 1, ms);
|
poll((struct pollfd[]){{ttyin, POLLIN}}, 1, ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnMouseWheelUp(struct Panel *p) {
|
static void OnMouseWheelUp(struct Panel *p, int y, int x) {
|
||||||
if (p == &pan.disassembly) {
|
if (p == &pan.disassembly) {
|
||||||
opstart -= WHEELDELTA;
|
opstart -= WHEELDELTA;
|
||||||
} else if (p == &pan.code) {
|
} else if (p == &pan.code) {
|
||||||
|
@ -2241,7 +2265,7 @@ static void OnMouseWheelUp(struct Panel *p) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnMouseWheelDown(struct Panel *p) {
|
static void OnMouseWheelDown(struct Panel *p, int y, int x) {
|
||||||
if (p == &pan.disassembly) {
|
if (p == &pan.disassembly) {
|
||||||
opstart += WHEELDELTA;
|
opstart += WHEELDELTA;
|
||||||
} else if (p == &pan.code) {
|
} else if (p == &pan.code) {
|
||||||
|
@ -2261,12 +2285,12 @@ static void OnMouseWheelDown(struct Panel *p) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnMouseCtrlWheelUp(struct Panel *p) {
|
static void OnMouseCtrlWheelUp(struct Panel *p, int y, int x) {
|
||||||
ZoomMemoryViews(p, -1);
|
ZoomMemoryViews(p, y, x, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnMouseCtrlWheelDown(struct Panel *p) {
|
static void OnMouseCtrlWheelDown(struct Panel *p, int y, int x) {
|
||||||
ZoomMemoryViews(p, +1);
|
ZoomMemoryViews(p, y, x, +1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct Panel *LocatePanel(int y, int x) {
|
static struct Panel *LocatePanel(int y, int x) {
|
||||||
|
@ -2290,18 +2314,20 @@ static void OnMouse(char *p) {
|
||||||
y = min(tyn, max(1, strtol(p, &p, 10))) - 1;
|
y = min(tyn, max(1, strtol(p, &p, 10))) - 1;
|
||||||
e |= (*p == 'm') << 2;
|
e |= (*p == 'm') << 2;
|
||||||
if ((ep = LocatePanel(y, x))) {
|
if ((ep = LocatePanel(y, x))) {
|
||||||
|
y -= ep->top;
|
||||||
|
x -= ep->left;
|
||||||
switch (e) {
|
switch (e) {
|
||||||
case kMouseWheelUp:
|
case kMouseWheelUp:
|
||||||
OnMouseWheelUp(ep);
|
OnMouseWheelUp(ep, y, x);
|
||||||
break;
|
break;
|
||||||
case kMouseWheelDown:
|
case kMouseWheelDown:
|
||||||
OnMouseWheelDown(ep);
|
OnMouseWheelDown(ep, y, x);
|
||||||
break;
|
break;
|
||||||
case kMouseCtrlWheelUp:
|
case kMouseCtrlWheelUp:
|
||||||
OnMouseCtrlWheelUp(ep);
|
OnMouseCtrlWheelUp(ep, y, x);
|
||||||
break;
|
break;
|
||||||
case kMouseCtrlWheelDown:
|
case kMouseCtrlWheelDown:
|
||||||
OnMouseCtrlWheelDown(ep);
|
OnMouseCtrlWheelDown(ep, y, x);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=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 │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
|
#include "libc/log/check.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes file system caches from RAM.
|
||||||
|
*
|
||||||
|
* make o//tool/build/dropcache.com
|
||||||
|
* sudo mv o//tool/build/dropcache.com /usr/local/bin/
|
||||||
|
* sudo chown root /usr/local/bin/dropcache.com
|
||||||
|
* sudo chmod u+s /usr/local/bin/dropcache.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void Write(int fd, const char *s) {
|
||||||
|
write(fd, s, strlen(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
int fd;
|
||||||
|
sync();
|
||||||
|
fd = open("/proc/sys/vm/drop_caches", O_WRONLY);
|
||||||
|
if (fd == -1) {
|
||||||
|
if (errno == EACCES) {
|
||||||
|
Write(1, "error: need root privileges\n");
|
||||||
|
} else if (errno == ENOENT) {
|
||||||
|
Write(1, "error: need /proc filesystem\n");
|
||||||
|
}
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
Write(fd, "3\n");
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -74,8 +74,8 @@ static void DisLoadElfSyms(struct Dis *d, struct Elf *elf) {
|
||||||
const Elf64_Sym *st, *sym;
|
const Elf64_Sym *st, *sym;
|
||||||
bool isabs, iscode, isweak, islocal, ishidden, isprotected, isfunc, isobject;
|
bool isabs, iscode, isweak, islocal, ishidden, isprotected, isfunc, isobject;
|
||||||
j = 0;
|
j = 0;
|
||||||
if ((d->syms.stab = getelfstringtable(elf->ehdr, elf->size)) &&
|
if ((d->syms.stab = GetElfStringTable(elf->ehdr, elf->size)) &&
|
||||||
(st = getelfsymboltable(elf->ehdr, elf->size, &n))) {
|
(st = GetElfSymbolTable(elf->ehdr, elf->size, &n))) {
|
||||||
stablen = (intptr_t)elf->ehdr + elf->size - (intptr_t)d->syms.stab;
|
stablen = (intptr_t)elf->ehdr + elf->size - (intptr_t)d->syms.stab;
|
||||||
if (d->syms.n < n) {
|
if (d->syms.n < n) {
|
||||||
d->syms.n = n;
|
d->syms.n = n;
|
||||||
|
|
|
@ -238,8 +238,8 @@ const char *DisSpecMap0(struct XedDecodedInst *x, char *p) {
|
||||||
RCASE(0xCB, "lret");
|
RCASE(0xCB, "lret");
|
||||||
RCASE(0xCC, "int3");
|
RCASE(0xCC, "int3");
|
||||||
RCASE(0xCD, "int Ib");
|
RCASE(0xCD, "int Ib");
|
||||||
RCASE(0xD0, "BIT Eb $1");
|
RCASE(0xD0, "BIT Eb");
|
||||||
RCASE(0xD1, "BIT Evqp $1");
|
RCASE(0xD1, "BIT Evqp");
|
||||||
RCASE(0xD2, "BIT Evqp %cl");
|
RCASE(0xD2, "BIT Evqp %cl");
|
||||||
RCASE(0xD3, "BIT Evqp %cl");
|
RCASE(0xD3, "BIT Evqp %cl");
|
||||||
RCASE(0xD4, x->op.uimm0 == 0x0a ? "aam" : "aam Ib");
|
RCASE(0xD4, x->op.uimm0 == 0x0a ? "aam" : "aam Ib");
|
||||||
|
|
|
@ -178,7 +178,7 @@ struct ElfWriter *elfwriter_open(const char *path, int mode) {
|
||||||
void elfwriter_close(struct ElfWriter *elf) {
|
void elfwriter_close(struct ElfWriter *elf) {
|
||||||
size_t i;
|
size_t i;
|
||||||
FlushTables(elf);
|
FlushTables(elf);
|
||||||
CHECK_NE(-1, msync(elf->map, elf->wrote, MS_SYNC));
|
CHECK_NE(-1, msync(elf->map, elf->wrote, MS_ASYNC));
|
||||||
CHECK_NE(-1, munmap(elf->map, elf->mapsize));
|
CHECK_NE(-1, munmap(elf->map, elf->mapsize));
|
||||||
CHECK_NE(-1, ftruncate(elf->fd, elf->wrote));
|
CHECK_NE(-1, ftruncate(elf->fd, elf->wrote));
|
||||||
CHECK_NE(-1, close(elf->fd));
|
CHECK_NE(-1, close(elf->fd));
|
||||||
|
|
|
@ -137,40 +137,24 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
|
||||||
int fd;
|
int fd;
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
int64_t sp;
|
int64_t sp;
|
||||||
char *real;
|
|
||||||
void *stack;
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
size_t i, codesize, mappedsize, extrasize;
|
size_t i, mappedsize;
|
||||||
DCHECK_NOTNULL(prog);
|
DCHECK_NOTNULL(prog);
|
||||||
elf->prog = prog;
|
elf->prog = prog;
|
||||||
if ((fd = open(prog, O_RDONLY)) == -1 ||
|
if ((fd = open(prog, O_RDONLY)) == -1 ||
|
||||||
(fstat(fd, &st) == -1 || !st.st_size) /* || !S_ISREG(st.st_mode) */) {
|
(fstat(fd, &st) == -1 || !st.st_size)) {
|
||||||
fputs(prog, stderr);
|
fputs(prog, stderr);
|
||||||
fputs(": not found\n", stderr);
|
fputs(": not found\n", stderr);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
codesize = st.st_size;
|
elf->mapsize = st.st_size;
|
||||||
elf->mapsize = ROUNDDOWN(codesize, FRAMESIZE);
|
|
||||||
extrasize = codesize - elf->mapsize;
|
|
||||||
elf->map = real = (char *)0x0000400000000000;
|
|
||||||
if (elf->mapsize) {
|
|
||||||
CHECK_NE(MAP_FAILED, mmap(real, elf->mapsize, PROT_READ | PROT_WRITE,
|
|
||||||
MAP_PRIVATE | MAP_FIXED, fd, 0));
|
|
||||||
real += elf->mapsize;
|
|
||||||
}
|
|
||||||
if (extrasize) {
|
|
||||||
CHECK_NE(MAP_FAILED,
|
CHECK_NE(MAP_FAILED,
|
||||||
mmap(real, ROUNDUP(extrasize, FRAMESIZE), PROT_READ | PROT_WRITE,
|
(elf->map = mmap(NULL, elf->mapsize, PROT_READ | PROT_WRITE,
|
||||||
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0));
|
MAP_PRIVATE, fd, 0)));
|
||||||
for (i = 0; i < extrasize; i += (size_t)rc) {
|
|
||||||
CHECK_NE(-1, (rc = pread(fd, real + i, extrasize - i, elf->mapsize + i)));
|
|
||||||
}
|
|
||||||
elf->mapsize += ROUNDUP(extrasize, FRAMESIZE);
|
|
||||||
}
|
|
||||||
CHECK_NE(-1, close(fd));
|
CHECK_NE(-1, close(fd));
|
||||||
ResetCpu(m);
|
ResetCpu(m);
|
||||||
if ((m->mode & 3) == XED_MODE_REAL) {
|
if ((m->mode & 3) == XED_MODE_REAL) {
|
||||||
BootProgram(m, elf, codesize);
|
BootProgram(m, elf, elf->mapsize);
|
||||||
} else {
|
} else {
|
||||||
sp = 0x800000000000;
|
sp = 0x800000000000;
|
||||||
Write64(m->sp, sp);
|
Write64(m->sp, sp);
|
||||||
|
@ -179,13 +163,13 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars,
|
||||||
LoadArgv(m, prog, args, vars);
|
LoadArgv(m, prog, args, vars);
|
||||||
if (memcmp(elf->map, "\177ELF", 4) == 0) {
|
if (memcmp(elf->map, "\177ELF", 4) == 0) {
|
||||||
elf->ehdr = (void *)elf->map;
|
elf->ehdr = (void *)elf->map;
|
||||||
elf->size = codesize;
|
elf->size = elf->mapsize;
|
||||||
LoadElf(m, elf);
|
LoadElf(m, elf);
|
||||||
} else {
|
} else {
|
||||||
elf->base = IMAGE_BASE_VIRTUAL;
|
elf->base = IMAGE_BASE_VIRTUAL;
|
||||||
elf->ehdr = NULL;
|
elf->ehdr = NULL;
|
||||||
elf->size = 0;
|
elf->size = 0;
|
||||||
LoadBin(m, elf->base, prog, elf->map, codesize);
|
LoadBin(m, elf->base, prog, elf->map, elf->mapsize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,24 +109,24 @@ struct Packages {
|
||||||
struct Package {
|
struct Package {
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
int32_t abi;
|
int32_t abi;
|
||||||
uint32_t path; /* pkg->strings.p[path] */
|
uint32_t path; // pkg->strings.p[path]
|
||||||
int64_t fd; /* not persisted */
|
int64_t fd; // not persisted
|
||||||
void *addr; /* not persisted */
|
void *addr; // not persisted
|
||||||
size_t size; /* not persisted */
|
size_t size; // not persisted
|
||||||
struct Strings {
|
struct Strings {
|
||||||
size_t i, n;
|
size_t i, n;
|
||||||
char *p; /* persisted as pkg+RVA */
|
char *p; // persisted as pkg+RVA
|
||||||
} strings; /* TODO(jart): interning? */
|
} strings; // TODO(jart): interning?
|
||||||
struct Objects {
|
struct Objects {
|
||||||
size_t i, n;
|
size_t i, n;
|
||||||
struct Object {
|
struct Object {
|
||||||
uint32_t path; /* pkg->strings.p[path] */
|
uint32_t path; // pkg->strings.p[path]
|
||||||
int64_t fd; /* not persisted */
|
unsigned mode; // not persisted
|
||||||
struct Elf64_Ehdr *elf; /* not persisted */
|
struct Elf64_Ehdr *elf; // not persisted
|
||||||
size_t size; /* not persisted */
|
size_t size; // not persisted
|
||||||
char *strs; /* not persisted */
|
char *strs; // not persisted
|
||||||
Elf64_Sym *syms; /* not persisted */
|
Elf64_Sym *syms; // not persisted
|
||||||
Elf64_Xword symcount; /* not persisted */
|
Elf64_Xword symcount; // not persisted
|
||||||
struct Sections {
|
struct Sections {
|
||||||
size_t i, n;
|
size_t i, n;
|
||||||
struct Section {
|
struct Section {
|
||||||
|
@ -149,20 +149,20 @@ struct Packages {
|
||||||
} * p;
|
} * p;
|
||||||
} ops;
|
} ops;
|
||||||
} * p;
|
} * p;
|
||||||
} sections; /* not persisted */
|
} sections; // not persisted
|
||||||
} * p; /* persisted as pkg+RVA */
|
} * p; // persisted as pkg+RVA
|
||||||
} objects;
|
} objects;
|
||||||
struct Symbols {
|
struct Symbols {
|
||||||
size_t i, n;
|
size_t i, n;
|
||||||
struct Symbol {
|
struct Symbol {
|
||||||
uint32_t name; /* pkg->strings.p[name] */
|
uint32_t name; // pkg->strings.p[name]
|
||||||
enum SectionKind kind : 8;
|
enum SectionKind kind : 8;
|
||||||
uint8_t bind : 4;
|
uint8_t bind : 4;
|
||||||
uint8_t type : 4;
|
uint8_t type : 4;
|
||||||
uint16_t object; /* pkg->objects.p[object] */
|
uint16_t object; // pkg->objects.p[object]
|
||||||
} * p; /* persisted as pkg+RVA */
|
} * p; // persisted as pkg+RVA
|
||||||
} symbols, undefs; /* TODO(jart): hash undefs? */
|
} symbols, undefs; // TODO(jart): hash undefs?
|
||||||
} * *p; /* persisted across multiple files */
|
} * *p; // persisted across multiple files
|
||||||
};
|
};
|
||||||
|
|
||||||
int CompareSymbolName(const struct Symbol *a, const struct Symbol *b,
|
int CompareSymbolName(const struct Symbol *a, const struct Symbol *b,
|
||||||
|
@ -265,7 +265,7 @@ void IndexSections(struct Object *obj) {
|
||||||
memset(§, 0, sizeof(sect));
|
memset(§, 0, sizeof(sect));
|
||||||
CHECK_NOTNULL((shdr = getelfsectionheaderaddress(obj->elf, obj->size, i)));
|
CHECK_NOTNULL((shdr = getelfsectionheaderaddress(obj->elf, obj->size, i)));
|
||||||
if (shdr->sh_type != SHT_NULL) {
|
if (shdr->sh_type != SHT_NULL) {
|
||||||
CHECK_NOTNULL((name = getelfsectionname(obj->elf, obj->size, shdr)));
|
CHECK_NOTNULL((name = GetElfSectionName(obj->elf, obj->size, shdr)));
|
||||||
if (startswith(name, ".sort.")) name += 5;
|
if (startswith(name, ".sort.")) name += 5;
|
||||||
if ((strcmp(name, ".piro.relo") == 0 ||
|
if ((strcmp(name, ".piro.relo") == 0 ||
|
||||||
startswith(name, ".piro.relo.")) ||
|
startswith(name, ".piro.relo.")) ||
|
||||||
|
@ -329,7 +329,7 @@ void LoadSymbols(struct Package *pkg, uint32_t object) {
|
||||||
if (symbol.bind != STB_LOCAL &&
|
if (symbol.bind != STB_LOCAL &&
|
||||||
(symbol.type == STT_OBJECT || symbol.type == STT_FUNC ||
|
(symbol.type == STT_OBJECT || symbol.type == STT_FUNC ||
|
||||||
symbol.type == STT_COMMON || symbol.type == STT_NOTYPE)) {
|
symbol.type == STT_COMMON || symbol.type == STT_NOTYPE)) {
|
||||||
name = getelfstring(obj->elf, obj->size, obj->strs, obj->syms[i].st_name);
|
name = GetElfString(obj->elf, obj->size, obj->strs, obj->syms[i].st_name);
|
||||||
DEBUGF("%s", name);
|
DEBUGF("%s", name);
|
||||||
if (strcmp(name, "_GLOBAL_OFFSET_TABLE_") != 0) {
|
if (strcmp(name, "_GLOBAL_OFFSET_TABLE_") != 0) {
|
||||||
symbol.kind = ClassifySection(obj, symbol.type, obj->syms[i].st_shndx);
|
symbol.kind = ClassifySection(obj, symbol.type, obj->syms[i].st_shndx);
|
||||||
|
@ -347,23 +347,25 @@ void OpenObject(struct Package *pkg, struct Object *obj, int mode, int prot,
|
||||||
int flags) {
|
int flags) {
|
||||||
int fd;
|
int fd;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
CHECK_NE(-1, (fd = open(&pkg->strings.p[obj->path], mode)), "path=%`'s",
|
CHECK_NE(-1, (fd = open(&pkg->strings.p[obj->path], (obj->mode = mode))),
|
||||||
&pkg->strings.p[obj->path]);
|
"path=%`'s", &pkg->strings.p[obj->path]);
|
||||||
CHECK_NE(-1, fstat(fd, &st));
|
CHECK_NE(-1, fstat(fd, &st));
|
||||||
CHECK_NE(MAP_FAILED, (obj->elf = mmap(NULL, (obj->size = st.st_size), prot,
|
CHECK_NE(MAP_FAILED, (obj->elf = mmap(NULL, (obj->size = st.st_size), prot,
|
||||||
flags, fd, 0)));
|
flags, fd, 0)));
|
||||||
CHECK_NE(-1, close(fd));
|
CHECK_NE(-1, close(fd));
|
||||||
CHECK(iself64binary(obj->elf, obj->size), "path=%`'s",
|
CHECK(IsElf64Binary(obj->elf, obj->size), "path=%`'s",
|
||||||
&pkg->strings.p[obj->path]);
|
&pkg->strings.p[obj->path]);
|
||||||
CHECK_NOTNULL((obj->strs = getelfstringtable(obj->elf, obj->size)));
|
CHECK_NOTNULL((obj->strs = GetElfStringTable(obj->elf, obj->size)));
|
||||||
CHECK_NOTNULL(
|
CHECK_NOTNULL(
|
||||||
(obj->syms = getelfsymboltable(obj->elf, obj->size, &obj->symcount)));
|
(obj->syms = GetElfSymbolTable(obj->elf, obj->size, &obj->symcount)));
|
||||||
CHECK_NE(0, obj->symcount);
|
CHECK_NE(0, obj->symcount);
|
||||||
IndexSections(obj);
|
IndexSections(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CloseObject(struct Object *obj) {
|
void CloseObject(struct Object *obj) {
|
||||||
msync(obj->elf, obj->size, MS_SYNC);
|
if ((obj->mode & O_ACCMODE) != O_RDONLY) {
|
||||||
|
CHECK_NE(-1, msync(obj->elf, obj->size, MS_ASYNC | MS_INVALIDATE));
|
||||||
|
}
|
||||||
CHECK_NE(-1, munmap(obj->elf, obj->size));
|
CHECK_NE(-1, munmap(obj->elf, obj->size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,7 +479,7 @@ void OptimizeRelocations(struct Package *pkg, struct Packages *deps,
|
||||||
if ((ELF64_R_TYPE(rela->r_info) == R_X86_64_PC32 ||
|
if ((ELF64_R_TYPE(rela->r_info) == R_X86_64_PC32 ||
|
||||||
ELF64_R_TYPE(rela->r_info) == R_X86_64_GOTPCREL) &&
|
ELF64_R_TYPE(rela->r_info) == R_X86_64_GOTPCREL) &&
|
||||||
FindSymbol(
|
FindSymbol(
|
||||||
getelfstring(obj->elf, obj->size, obj->strs,
|
GetElfString(obj->elf, obj->size, obj->strs,
|
||||||
obj->syms[ELF64_R_SYM(rela->r_info)].st_name),
|
obj->syms[ELF64_R_SYM(rela->r_info)].st_name),
|
||||||
pkg, deps, &refpkg, &refsym) &&
|
pkg, deps, &refpkg, &refsym) &&
|
||||||
(refsym->kind == kData || refsym->kind == kBss) &&
|
(refsym->kind == kData || refsym->kind == kBss) &&
|
||||||
|
@ -500,7 +502,7 @@ void OptimizeRelocations(struct Package *pkg, struct Packages *deps,
|
||||||
* Then libc/runtime/ftrace.greg.c morphs it back at runtime.
|
* Then libc/runtime/ftrace.greg.c morphs it back at runtime.
|
||||||
*/
|
*/
|
||||||
if (ELF64_R_TYPE(rela->r_info) == R_X86_64_GOTPCRELX &&
|
if (ELF64_R_TYPE(rela->r_info) == R_X86_64_GOTPCRELX &&
|
||||||
strcmp(getelfstring(obj->elf, obj->size, obj->strs,
|
strcmp(GetElfString(obj->elf, obj->size, obj->strs,
|
||||||
obj->syms[ELF64_R_SYM(rela->r_info)].st_name),
|
obj->syms[ELF64_R_SYM(rela->r_info)].st_name),
|
||||||
"mcount") == 0) {
|
"mcount") == 0) {
|
||||||
rela->r_info = R_X86_64_NONE;
|
rela->r_info = R_X86_64_NONE;
|
||||||
|
@ -518,7 +520,7 @@ void OptimizeRelocations(struct Package *pkg, struct Packages *deps,
|
||||||
*/
|
*/
|
||||||
if ((ELF64_R_TYPE(rela->r_info) == R_X86_64_PC32 ||
|
if ((ELF64_R_TYPE(rela->r_info) == R_X86_64_PC32 ||
|
||||||
ELF64_R_TYPE(rela->r_info) == R_X86_64_PLT32) &&
|
ELF64_R_TYPE(rela->r_info) == R_X86_64_PLT32) &&
|
||||||
strcmp(getelfstring(obj->elf, obj->size, obj->strs,
|
strcmp(GetElfString(obj->elf, obj->size, obj->strs,
|
||||||
obj->syms[ELF64_R_SYM(rela->r_info)].st_name),
|
obj->syms[ELF64_R_SYM(rela->r_info)].st_name),
|
||||||
"mcount") == 0) {
|
"mcount") == 0) {
|
||||||
rela->r_info = R_X86_64_NONE;
|
rela->r_info = R_X86_64_NONE;
|
||||||
|
@ -598,7 +600,7 @@ void CompressLowEntropyReadOnlyDataSections(struct Package *pkg,
|
||||||
!(shdr->sh_flags &
|
!(shdr->sh_flags &
|
||||||
(SHF_WRITE | SHF_MERGE | SHF_STRINGS | SHF_COMPRESSED))) &&
|
(SHF_WRITE | SHF_MERGE | SHF_STRINGS | SHF_COMPRESSED))) &&
|
||||||
(p = getelfsectionaddress(obj->elf, obj->size, shdr)) &&
|
(p = getelfsectionaddress(obj->elf, obj->size, shdr)) &&
|
||||||
startswith((name = getelfsectionname(obj->elf, obj->size, shdr)),
|
startswith((name = GetElfSectionName(obj->elf, obj->size, shdr)),
|
||||||
".rodata") &&
|
".rodata") &&
|
||||||
rlencode(&rle, p, shdr->sh_size) != -1) {
|
rlencode(&rle, p, shdr->sh_size) != -1) {
|
||||||
isprofitable = rle.i * sizeof(rle.p[0]) <= shdr->sh_size / 2;
|
isprofitable = rle.i * sizeof(rle.p[0]) <= shdr->sh_size / 2;
|
||||||
|
|
|
@ -312,6 +312,7 @@ void zipobj(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
showcrashreports();
|
||||||
zipobj(argc, argv);
|
zipobj(argc, argv);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||||
|
│vi: set net ft=c ts=2 sts=2 sw=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 │
|
||||||
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/bits/bits.h"
|
||||||
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/calls/struct/stat.h"
|
||||||
|
#include "libc/conv/conv.h"
|
||||||
|
#include "libc/log/check.h"
|
||||||
|
#include "libc/log/log.h"
|
||||||
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
#include "libc/sysv/consts/map.h"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
|
#include "libc/sysv/consts/prot.h"
|
||||||
|
#include "libc/x/x.h"
|
||||||
|
|
||||||
|
#define AR_MAGIC1 "!<arch>\n"
|
||||||
|
#define AR_MAGIC2 "`\n"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ar rU doge.a NOTICE # create archive and use non-deterministic stuff
|
||||||
|
* o//tool/decode/ar.com doge.a
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int fd;
|
||||||
|
static uint8_t *data;
|
||||||
|
static long size;
|
||||||
|
static const char *path;
|
||||||
|
static struct stat st;
|
||||||
|
|
||||||
|
static void PrintString(uint8_t *p, long n, const char *name) {
|
||||||
|
char *s;
|
||||||
|
s = xmalloc(n + 1);
|
||||||
|
s[n] = '\0';
|
||||||
|
memcpy(s, p, n);
|
||||||
|
printf("\t.ascii\t%`'.*s\t\t\t# %s\n", n, s, name);
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Open(void) {
|
||||||
|
if ((fd = open(path, O_RDONLY)) == -1) {
|
||||||
|
fprintf(stderr, "error: open() failed: %s\n", path);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
CHECK_NE(-1, fstat(fd, &st));
|
||||||
|
if (!(size = st.st_size)) exit(0);
|
||||||
|
CHECK_NE(MAP_FAILED,
|
||||||
|
(data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0)));
|
||||||
|
LOGIFNEG1(close(fd));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Close(void) {
|
||||||
|
LOGIFNEG1(munmap(data, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Check(void) {
|
||||||
|
if (size < 8 + 60 + 4 ||
|
||||||
|
(memcmp(data, AR_MAGIC1, strlen(AR_MAGIC1)) != 0 ||
|
||||||
|
memcmp(data + 66, AR_MAGIC2, strlen(AR_MAGIC2)) != 0)) {
|
||||||
|
fprintf(stderr, "error: not a unix archive: %s\n", path);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PrintTable(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PrintHeader(uint8_t *p) {
|
||||||
|
PrintString(p + 0, 16, "file identifier [ascii]");
|
||||||
|
PrintString(p + 16, 12, "file modification timestamp [decimal]");
|
||||||
|
PrintString(p + 28, 6, "owner id [decimal]");
|
||||||
|
PrintString(p + 34, 6, "group id [decimal]");
|
||||||
|
PrintString(p + 40, 8, "file mode [octal] (type and permission)");
|
||||||
|
PrintString(p + 48, 10, "file size in bytes [decimal]");
|
||||||
|
PrintString(p + 58, 2, "ending characters");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Print(void) {
|
||||||
|
int arsize;
|
||||||
|
uint8_t *b, *p;
|
||||||
|
uint64_t offset;
|
||||||
|
uint32_t i, n, o, table, entries, symbols, symbolslen;
|
||||||
|
arsize = atoi((char *)(data + 8 + 48));
|
||||||
|
CHECK_LE(4, arsize);
|
||||||
|
CHECK_LE(8 + 60 + arsize, size);
|
||||||
|
entries = read32be(data + 8 + 60);
|
||||||
|
CHECK_LE(4 + entries * 4 + 1, arsize);
|
||||||
|
printf("\t# %'s\n", path);
|
||||||
|
PrintString(data, 8, "file signature");
|
||||||
|
PrintHeader(data + 8);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
printf("\t.long\t%u\t\t\t# %s\n", entries, "symbol table entries");
|
||||||
|
table = 8 + 60 + 4;
|
||||||
|
for (i = 0; i < entries; ++i) {
|
||||||
|
printf("\t.long\t%#x\t\t\t\t# %u\n", read32be(data + table + i * 4), i);
|
||||||
|
}
|
||||||
|
symbols = table + entries * 4;
|
||||||
|
symbolslen = arsize - (4 + entries * 4);
|
||||||
|
for (i = o = 0; o < symbolslen; ++i, o += n + 1) {
|
||||||
|
b = data + symbols + o;
|
||||||
|
CHECK_NOTNULL((p = memchr(b, '\0', symbolslen - (symbols + o))));
|
||||||
|
n = p - b;
|
||||||
|
printf("\t.asciz\t%#`'.*s\t\t\t# %u\n", n, b, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = 8 + 60 + arsize;
|
||||||
|
while (offset < size) {
|
||||||
|
offset += offset & 1;
|
||||||
|
CHECK_LE(offset + 60, size);
|
||||||
|
CHECK_EQ(0, memcmp(data + offset + 58, AR_MAGIC2, strlen(AR_MAGIC2)));
|
||||||
|
arsize = atoi((char *)(data + offset + 48));
|
||||||
|
CHECK_LE(offset + 60 + arsize, size);
|
||||||
|
printf("\n");
|
||||||
|
PrintHeader(data + offset);
|
||||||
|
offset += 60 + arsize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
if (argc < 2) return 1;
|
||||||
|
path = argv[1];
|
||||||
|
Open();
|
||||||
|
Check();
|
||||||
|
Print();
|
||||||
|
Close();
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -134,8 +134,8 @@ static void printelfsectionheader(int i, char *shstrtab) {
|
||||||
printf(".Lsh%d:", i);
|
printf(".Lsh%d:", i);
|
||||||
show(".long", format(b1, "%d", shdr->sh_name),
|
show(".long", format(b1, "%d", shdr->sh_name),
|
||||||
format(b2,
|
format(b2,
|
||||||
"%`'s == getelfstring(elf, st->st_size, shstrtab, shdr->sh_name)",
|
"%`'s == GetElfString(elf, st->st_size, shstrtab, shdr->sh_name)",
|
||||||
getelfstring(elf, st->st_size, shstrtab, shdr->sh_name)));
|
GetElfString(elf, st->st_size, shstrtab, shdr->sh_name)));
|
||||||
show(".long",
|
show(".long",
|
||||||
firstnonnull(findnamebyid(kElfSectionTypeNames, shdr->sh_type),
|
firstnonnull(findnamebyid(kElfSectionTypeNames, shdr->sh_type),
|
||||||
format(b1, "%d", shdr->sh_type)),
|
format(b1, "%d", shdr->sh_type)),
|
||||||
|
@ -167,7 +167,7 @@ static void printelfsectionheaders(void) {
|
||||||
->sh_offset);
|
->sh_offset);
|
||||||
for (i = 0; i < elf->e_shnum; ++i) {
|
for (i = 0; i < elf->e_shnum; ++i) {
|
||||||
Elf64_Shdr *shdr = getelfsectionheaderaddress(elf, st->st_size, i);
|
Elf64_Shdr *shdr = getelfsectionheaderaddress(elf, st->st_size, i);
|
||||||
const char *str = getelfstring(elf, st->st_size, shstrtab, shdr->sh_name);
|
const char *str = GetElfString(elf, st->st_size, shstrtab, shdr->sh_name);
|
||||||
show(".asciz", format(b1, "%`'s", str), NULL);
|
show(".asciz", format(b1, "%`'s", str), NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,14 +199,14 @@ static void printelfsymbolother(Elf64_Sym *sym) {
|
||||||
static void printelfsymbol(Elf64_Sym *sym, char *strtab, char *shstrtab) {
|
static void printelfsymbol(Elf64_Sym *sym, char *strtab, char *shstrtab) {
|
||||||
show(".long", format(b1, "%d", sym->st_name),
|
show(".long", format(b1, "%d", sym->st_name),
|
||||||
format(b2, "%`'s (sym->st_name)",
|
format(b2, "%`'s (sym->st_name)",
|
||||||
getelfstring(elf, st->st_size, strtab, sym->st_name)));
|
GetElfString(elf, st->st_size, strtab, sym->st_name)));
|
||||||
printelfsymbolinfo(sym);
|
printelfsymbolinfo(sym);
|
||||||
printelfsymbolother(sym);
|
printelfsymbolother(sym);
|
||||||
show(".short", format(b1, "%d", sym->st_shndx),
|
show(".short", format(b1, "%d", sym->st_shndx),
|
||||||
format(b2, "%s sym->st_shndx",
|
format(b2, "%s sym->st_shndx",
|
||||||
sym->st_shndx < 0xff00
|
sym->st_shndx < 0xff00
|
||||||
? format(b1, "%`'s",
|
? format(b1, "%`'s",
|
||||||
getelfstring(elf, st->st_size, shstrtab,
|
GetElfString(elf, st->st_size, shstrtab,
|
||||||
getelfsectionheaderaddress(
|
getelfsectionheaderaddress(
|
||||||
elf, st->st_size, sym->st_shndx)
|
elf, st->st_size, sym->st_shndx)
|
||||||
->sh_name))
|
->sh_name))
|
||||||
|
@ -217,8 +217,8 @@ static void printelfsymbol(Elf64_Sym *sym, char *strtab, char *shstrtab) {
|
||||||
|
|
||||||
static void printelfsymboltable(void) {
|
static void printelfsymboltable(void) {
|
||||||
size_t i, symcount = 0;
|
size_t i, symcount = 0;
|
||||||
Elf64_Sym *symtab = getelfsymboltable(elf, st->st_size, &symcount);
|
Elf64_Sym *symtab = GetElfSymbolTable(elf, st->st_size, &symcount);
|
||||||
char *strtab = getelfstringtable(elf, st->st_size);
|
char *strtab = GetElfStringTable(elf, st->st_size);
|
||||||
char *shstrtab = getelfsectionnamestringtable(elf, st->st_size);
|
char *shstrtab = getelfsectionnamestringtable(elf, st->st_size);
|
||||||
if (symtab && strtab) {
|
if (symtab && strtab) {
|
||||||
printf("\n\n");
|
printf("\n\n");
|
||||||
|
@ -239,8 +239,8 @@ static char *getelfsymbolname(const Elf64_Ehdr *elf, size_t mapsize,
|
||||||
((shstrtab && !sym->st_name &&
|
((shstrtab && !sym->st_name &&
|
||||||
ELF64_ST_TYPE(sym->st_info) == STT_SECTION &&
|
ELF64_ST_TYPE(sym->st_info) == STT_SECTION &&
|
||||||
(shdr = getelfsectionheaderaddress(elf, mapsize, sym->st_shndx)) &&
|
(shdr = getelfsectionheaderaddress(elf, mapsize, sym->st_shndx)) &&
|
||||||
(res = getelfstring(elf, mapsize, shstrtab, shdr->sh_name))) ||
|
(res = GetElfString(elf, mapsize, shstrtab, shdr->sh_name))) ||
|
||||||
(strtab && (res = getelfstring(elf, mapsize, strtab, sym->st_name))))) {
|
(strtab && (res = GetElfString(elf, mapsize, strtab, sym->st_name))))) {
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -254,13 +254,13 @@ static void printelfrelocations(void) {
|
||||||
const Elf64_Rela *rela;
|
const Elf64_Rela *rela;
|
||||||
const Elf64_Shdr *shdr, *boop;
|
const Elf64_Shdr *shdr, *boop;
|
||||||
char *strtab, *shstrtab, *symbolname;
|
char *strtab, *shstrtab, *symbolname;
|
||||||
strtab = getelfstringtable(elf, st->st_size);
|
strtab = GetElfStringTable(elf, st->st_size);
|
||||||
shstrtab = getelfsectionnamestringtable(elf, st->st_size);
|
shstrtab = getelfsectionnamestringtable(elf, st->st_size);
|
||||||
for (i = 0; i < elf->e_shnum; ++i) {
|
for (i = 0; i < elf->e_shnum; ++i) {
|
||||||
if ((shdr = getelfsectionheaderaddress(elf, st->st_size, i)) &&
|
if ((shdr = getelfsectionheaderaddress(elf, st->st_size, i)) &&
|
||||||
shdr->sh_type == SHT_RELA &&
|
shdr->sh_type == SHT_RELA &&
|
||||||
(rela = getelfsectionaddress(elf, st->st_size, shdr))) {
|
(rela = getelfsectionaddress(elf, st->st_size, shdr))) {
|
||||||
printf("\n/\t%s\n", getelfsectionname(elf, st->st_size, shdr));
|
printf("\n/\t%s\n", GetElfSectionName(elf, st->st_size, shdr));
|
||||||
printf("\t.org\t%#x\n", (intptr_t)rela - (intptr_t)elf);
|
printf("\t.org\t%#x\n", (intptr_t)rela - (intptr_t)elf);
|
||||||
for (j = 0; ((uintptr_t)rela + sizeof(Elf64_Rela) <=
|
for (j = 0; ((uintptr_t)rela + sizeof(Elf64_Rela) <=
|
||||||
min((uintptr_t)elf + st->st_size,
|
min((uintptr_t)elf + st->st_size,
|
||||||
|
@ -272,7 +272,7 @@ static void printelfrelocations(void) {
|
||||||
symbolname =
|
symbolname =
|
||||||
getelfsymbolname(elf, st->st_size, strtab, shstrtab, &syms[sym]);
|
getelfsymbolname(elf, st->st_size, strtab, shstrtab, &syms[sym]);
|
||||||
printf("/\t%s+%#lx → %s%c%#lx\n",
|
printf("/\t%s+%#lx → %s%c%#lx\n",
|
||||||
getelfstring(
|
GetElfString(
|
||||||
elf, st->st_size, shstrtab,
|
elf, st->st_size, shstrtab,
|
||||||
getelfsectionheaderaddress(elf, st->st_size, shdr->sh_info)
|
getelfsectionheaderaddress(elf, st->st_size, shdr->sh_info)
|
||||||
->sh_name),
|
->sh_name),
|
||||||
|
|
|
@ -68,6 +68,6 @@ kPollNames:
|
||||||
lodsl
|
lodsl
|
||||||
add %rbx,%rax # %rbx is image base (cosmo abi)
|
add %rbx,%rax # %rbx is image base (cosmo abi)
|
||||||
stosq
|
stosq
|
||||||
loop 0b
|
.loop 0b
|
||||||
add $16,%rdi
|
add $16,%rdi
|
||||||
.init.end 301,_init_kPollNames
|
.init.end 301,_init_kPollNames
|
||||||
|
|
Loading…
Reference in New Issue