mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 06:48:31 +00:00
Initial import
This commit is contained in:
commit
c91b3c5006
14915 changed files with 590219 additions and 0 deletions
58
tool/build/lib/buildlib.mk
Normal file
58
tool/build/lib/buildlib.mk
Normal file
|
@ -0,0 +1,58 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += TOOL_BUILD_LIB
|
||||
|
||||
TOOL_BUILD_LIB_ARTIFACTS += TOOL_BUILD_LIB_A
|
||||
TOOL_BUILD_LIB = $(TOOL_BUILD_LIB_A_DEPS) $(TOOL_BUILD_LIB_A)
|
||||
TOOL_BUILD_LIB_A = o/$(MODE)/tool/build/lib/buildlib.a
|
||||
TOOL_BUILD_LIB_A_FILES := $(wildcard tool/build/lib/*)
|
||||
TOOL_BUILD_LIB_A_HDRS = $(filter %.h,$(TOOL_BUILD_LIB_A_FILES))
|
||||
TOOL_BUILD_LIB_A_SRCS_S = $(filter %.S,$(TOOL_BUILD_LIB_A_FILES))
|
||||
TOOL_BUILD_LIB_A_SRCS_C = $(filter %.c,$(TOOL_BUILD_LIB_A_FILES))
|
||||
TOOL_BUILD_LIB_A_CHECKS = $(TOOL_BUILD_LIB_A).pkg
|
||||
|
||||
TOOL_BUILD_LIB_A_SRCS = \
|
||||
$(TOOL_BUILD_LIB_A_SRCS_S) \
|
||||
$(TOOL_BUILD_LIB_A_SRCS_C)
|
||||
|
||||
TOOL_BUILD_LIB_A_OBJS = \
|
||||
$(TOOL_BUILD_LIB_A_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(TOOL_BUILD_LIB_A_SRCS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(TOOL_BUILD_LIB_A_SRCS_C:%.c=o/$(MODE)/%.o)
|
||||
|
||||
TOOL_BUILD_LIB_A_DIRECTDEPS = \
|
||||
LIBC_CALLS \
|
||||
LIBC_CALLS_HEFTY \
|
||||
LIBC_FMT \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_LOG \
|
||||
LIBC_X
|
||||
|
||||
TOOL_BUILD_LIB_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(TOOL_BUILD_LIB_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(TOOL_BUILD_LIB_A): \
|
||||
tool/build/lib/ \
|
||||
$(TOOL_BUILD_LIB_A).pkg \
|
||||
$(TOOL_BUILD_LIB_A_OBJS)
|
||||
|
||||
$(TOOL_BUILD_LIB_A).pkg: \
|
||||
$(TOOL_BUILD_LIB_A_OBJS) \
|
||||
$(foreach x,$(TOOL_BUILD_LIB_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
TOOL_BUILD_LIB_LIBS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)))
|
||||
TOOL_BUILD_LIB_SRCS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_SRCS))
|
||||
TOOL_BUILD_LIB_HDRS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_HDRS))
|
||||
TOOL_BUILD_LIB_BINS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_BINS))
|
||||
TOOL_BUILD_LIB_CHECKS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_CHECKS))
|
||||
TOOL_BUILD_LIB_OBJS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_OBJS))
|
||||
TOOL_BUILD_LIB_TESTS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_TESTS))
|
||||
|
||||
.PHONY: o/$(MODE)/tool/build/lib
|
||||
o/$(MODE)/tool/build/lib: $(TOOL_BUILD_LIB_CHECKS)
|
259
tool/build/lib/elfwriter.c
Normal file
259
tool/build/lib/elfwriter.c
Normal file
|
@ -0,0 +1,259 @@
|
|||
/*-*- 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/arraylist.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/runtime/mappings.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/mremap.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/elfwriter.h"
|
||||
#include "tool/build/lib/interner.h"
|
||||
|
||||
static const Elf64_Ehdr kObjHeader = {
|
||||
.e_ident = {ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, ELFCLASS64, ELFDATA2LSB, 1,
|
||||
ELFOSABI_NONE},
|
||||
.e_type = ET_REL,
|
||||
.e_machine = EM_NEXGEN32E,
|
||||
.e_version = 1,
|
||||
.e_ehsize = sizeof(Elf64_Ehdr),
|
||||
.e_shentsize = sizeof(Elf64_Shdr)};
|
||||
|
||||
static size_t AppendSection(struct ElfWriter *elf, const char *name,
|
||||
int sh_type, int sh_flags) {
|
||||
ssize_t section =
|
||||
append(elf->shdrs,
|
||||
(&(Elf64_Shdr){.sh_type = sh_type,
|
||||
.sh_flags = sh_flags,
|
||||
.sh_entsize = elf->entsize,
|
||||
.sh_addralign = elf->addralign,
|
||||
.sh_offset = sh_type != SHT_NULL ? elf->wrote : 0,
|
||||
.sh_name = intern(elf->shstrtab, name)}));
|
||||
CHECK_NE(-1, section);
|
||||
return section;
|
||||
}
|
||||
|
||||
static size_t FinishSection(struct ElfWriter *elf) {
|
||||
size_t section = elf->shdrs->i - 1;
|
||||
elf->shdrs->p[section].sh_size =
|
||||
elf->wrote - elf->shdrs->p[section].sh_offset;
|
||||
return section;
|
||||
}
|
||||
|
||||
static struct ElfWriterSymRef AppendSymbol(struct ElfWriter *elf,
|
||||
const char *name, int st_info,
|
||||
int st_other, size_t st_value,
|
||||
size_t st_size, size_t st_shndx,
|
||||
enum ElfWriterSymOrder slg) {
|
||||
ssize_t sym =
|
||||
append(elf->syms[slg], (&(Elf64_Sym){.st_info = st_info,
|
||||
.st_size = st_size,
|
||||
.st_value = st_value,
|
||||
.st_other = st_other,
|
||||
.st_name = intern(elf->strtab, name),
|
||||
.st_shndx = st_shndx}));
|
||||
CHECK_NE(-1, sym);
|
||||
return (struct ElfWriterSymRef){.slg = slg, .sym = sym};
|
||||
}
|
||||
|
||||
static void MakeRelaSection(struct ElfWriter *elf, size_t section) {
|
||||
size_t shdr, size;
|
||||
size = (elf->relas->i - elf->relas->j) * sizeof(Elf64_Rela);
|
||||
elfwriter_align(elf, alignof(Elf64_Rela), sizeof(Elf64_Rela));
|
||||
shdr = elfwriter_startsection(
|
||||
elf,
|
||||
gc(xasprintf("%s%s", ".rela",
|
||||
&elf->shstrtab->p[elf->shdrs->p[section].sh_name])),
|
||||
SHT_RELA, SHF_INFO_LINK);
|
||||
elf->shdrs->p[shdr].sh_info = section;
|
||||
elfwriter_reserve(elf, size);
|
||||
elfwriter_commit(elf, size);
|
||||
FinishSection(elf);
|
||||
elf->relas->j = elf->relas->i;
|
||||
}
|
||||
|
||||
static void WriteRelaSections(struct ElfWriter *elf, size_t symtab) {
|
||||
uint32_t sym;
|
||||
size_t i, j, k;
|
||||
Elf64_Rela *rela;
|
||||
for (j = 0, i = 0; i < elf->shdrs->i; ++i) {
|
||||
if (elf->shdrs->p[i].sh_type == SHT_RELA) {
|
||||
elf->shdrs->p[i].sh_link = symtab;
|
||||
for (rela = (Elf64_Rela *)((char *)elf->map + elf->shdrs->p[i].sh_offset);
|
||||
rela <
|
||||
(Elf64_Rela *)((char *)elf->map + (elf->shdrs->p[i].sh_offset +
|
||||
elf->shdrs->p[i].sh_size));
|
||||
rela++, j++) {
|
||||
sym = elf->relas->p[j].symkey.sym;
|
||||
for (k = 0; k < elf->relas->p[j].symkey.slg; ++k) {
|
||||
sym += elf->syms[k]->i;
|
||||
}
|
||||
rela->r_offset = elf->relas->p[j].offset;
|
||||
rela->r_info = ELF64_R_INFO(sym, elf->relas->p[j].type);
|
||||
rela->r_addend = elf->relas->p[j].addend;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(j == elf->relas->i);
|
||||
}
|
||||
|
||||
static size_t FlushStrtab(struct ElfWriter *elf, const char *name,
|
||||
struct Interner *strtab) {
|
||||
size_t size = strtab->i * sizeof(strtab->p[0]);
|
||||
elfwriter_align(elf, 1, 0);
|
||||
AppendSection(elf, ".strtab", SHT_STRTAB, 0);
|
||||
mempcpy(elfwriter_reserve(elf, size), strtab->p, size);
|
||||
elfwriter_commit(elf, size);
|
||||
return FinishSection(elf);
|
||||
}
|
||||
|
||||
static void FlushTables(struct ElfWriter *elf) {
|
||||
size_t i, size, symtab;
|
||||
elfwriter_align(elf, alignof(Elf64_Sym), sizeof(Elf64_Sym));
|
||||
symtab = AppendSection(elf, ".symtab", SHT_SYMTAB, 0);
|
||||
for (i = 0; i < ARRAYLEN(elf->syms); ++i) {
|
||||
size = elf->syms[i]->i * sizeof(Elf64_Sym);
|
||||
memcpy(elfwriter_reserve(elf, size), elf->syms[i]->p, size);
|
||||
elfwriter_commit(elf, size);
|
||||
}
|
||||
FinishSection(elf);
|
||||
elf->shdrs->p[symtab].sh_link = FlushStrtab(elf, ".strtab", elf->strtab);
|
||||
elf->ehdr->e_shstrndx = FlushStrtab(elf, ".shstrtab", elf->shstrtab);
|
||||
WriteRelaSections(elf, symtab);
|
||||
size = elf->shdrs->i * sizeof(elf->shdrs->p[0]);
|
||||
elfwriter_align(elf, alignof(elf->shdrs->p[0]), sizeof(elf->shdrs->p[0]));
|
||||
elf->ehdr->e_shoff = elf->wrote;
|
||||
elf->ehdr->e_shnum = elf->shdrs->i;
|
||||
elf->shdrs->p[symtab].sh_info =
|
||||
elf->syms[kElfWriterSymSection]->i + elf->syms[kElfWriterSymLocal]->i;
|
||||
mempcpy(elfwriter_reserve(elf, size), elf->shdrs->p, size);
|
||||
elfwriter_commit(elf, size);
|
||||
}
|
||||
|
||||
struct ElfWriter *elfwriter_open(const char *path, int mode) {
|
||||
struct ElfWriter *elf;
|
||||
CHECK_NOTNULL((elf = calloc(1, sizeof(struct ElfWriter))));
|
||||
CHECK_NOTNULL((elf->path = strdup(path)));
|
||||
CHECK_NE(-1, asprintf(&elf->tmppath, "%s.%d", elf->path, getpid()));
|
||||
CHECK_NE(-1, (elf->fd = open(elf->tmppath,
|
||||
O_CREAT | O_TRUNC | O_RDWR | O_EXCL, mode)));
|
||||
CHECK_NE(-1, ftruncate(elf->fd, (elf->mapsize = FRAMESIZE)));
|
||||
CHECK_NE(MAP_FAILED, (elf->map = mmap((void *)(intptr_t)kFixedMappingsStart,
|
||||
elf->mapsize, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_FIXED, elf->fd, 0)));
|
||||
elf->ehdr = memcpy(elf->map, &kObjHeader, (elf->wrote = sizeof(kObjHeader)));
|
||||
elf->strtab = newinterner();
|
||||
elf->shstrtab = newinterner();
|
||||
return elf;
|
||||
}
|
||||
|
||||
void elfwriter_close(struct ElfWriter *elf) {
|
||||
size_t i;
|
||||
FlushTables(elf);
|
||||
CHECK_NE(-1, munmap(elf->map, elf->mapsize));
|
||||
CHECK_NE(-1, ftruncate(elf->fd, elf->wrote));
|
||||
CHECK_NE(-1, close(elf->fd));
|
||||
CHECK_NE(-1, rename(elf->tmppath, elf->path));
|
||||
freeinterner(elf->shstrtab);
|
||||
freeinterner(elf->strtab);
|
||||
free(elf->shdrs->p);
|
||||
free(elf->relas->p);
|
||||
for (i = 0; i < ARRAYLEN(elf->syms); ++i) free(elf->syms[i]->p);
|
||||
free(elf);
|
||||
}
|
||||
|
||||
void elfwriter_align(struct ElfWriter *elf, size_t addralign, size_t entsize) {
|
||||
elf->entsize = entsize;
|
||||
elf->addralign = addralign;
|
||||
elf->wrote = roundup(elf->wrote, addralign);
|
||||
}
|
||||
|
||||
size_t elfwriter_startsection(struct ElfWriter *elf, const char *name,
|
||||
int sh_type, int sh_flags) {
|
||||
size_t shdr = AppendSection(elf, name, sh_type, sh_flags);
|
||||
AppendSymbol(elf, "",
|
||||
sh_type != SHT_NULL ? ELF64_ST_INFO(STB_LOCAL, STT_SECTION)
|
||||
: ELF64_ST_INFO(STB_LOCAL, STT_NOTYPE),
|
||||
STV_DEFAULT, 0, 0, shdr, kElfWriterSymSection);
|
||||
return shdr;
|
||||
}
|
||||
|
||||
void *elfwriter_reserve(struct ElfWriter *elf, size_t size) {
|
||||
size_t need, greed;
|
||||
need = elf->wrote + size;
|
||||
greed = elf->mapsize;
|
||||
if (need > greed) {
|
||||
do {
|
||||
greed = greed + (greed >> 1);
|
||||
} while (need > greed);
|
||||
greed = roundup(greed, FRAMESIZE);
|
||||
CHECK_NE(-1, ftruncate(elf->fd, greed));
|
||||
CHECK_NE(MAP_FAILED, mmap((char *)elf->map + elf->mapsize,
|
||||
greed - elf->mapsize, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_FIXED, elf->fd, elf->mapsize));
|
||||
elf->mapsize = greed;
|
||||
}
|
||||
return (char *)elf->map + elf->wrote;
|
||||
}
|
||||
|
||||
void elfwriter_commit(struct ElfWriter *elf, size_t size) {
|
||||
elf->wrote += size;
|
||||
}
|
||||
|
||||
void elfwriter_finishsection(struct ElfWriter *elf) {
|
||||
size_t section = FinishSection(elf);
|
||||
if (elf->relas->j < elf->relas->i) MakeRelaSection(elf, section);
|
||||
}
|
||||
|
||||
struct ElfWriterSymRef elfwriter_appendsym(struct ElfWriter *elf,
|
||||
const char *name, int st_info,
|
||||
int st_other, size_t st_value,
|
||||
size_t st_size) {
|
||||
return AppendSymbol(
|
||||
elf, name, st_info, st_other, st_value, st_size, elf->shdrs->i - 1,
|
||||
ELF64_ST_BIND(st_info) == STB_LOCAL ? kElfWriterSymLocal
|
||||
: kElfWriterSymGlobal);
|
||||
}
|
||||
|
||||
struct ElfWriterSymRef elfwriter_linksym(struct ElfWriter *elf,
|
||||
const char *name, int st_info,
|
||||
int st_other) {
|
||||
return AppendSymbol(elf, name, st_info, st_other, 0, 0, 0,
|
||||
kElfWriterSymGlobal);
|
||||
}
|
||||
|
||||
void elfwriter_appendrela(struct ElfWriter *elf, uint64_t r_offset,
|
||||
struct ElfWriterSymRef symkey, uint32_t type,
|
||||
int64_t r_addend) {
|
||||
CHECK_NE(-1,
|
||||
append(elf->relas, (&(struct ElfWriterRela){.type = type,
|
||||
.symkey = symkey,
|
||||
.offset = r_offset,
|
||||
.addend = r_addend})));
|
||||
}
|
67
tool/build/lib/elfwriter.h
Normal file
67
tool/build/lib/elfwriter.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_ELFWRITER_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_ELFWRITER_H_
|
||||
#include "libc/elf/struct/ehdr.h"
|
||||
#include "libc/elf/struct/rela.h"
|
||||
#include "libc/elf/struct/shdr.h"
|
||||
#include "libc/elf/struct/sym.h"
|
||||
#include "tool/build/lib/interner.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct ElfWriter {
|
||||
char *path;
|
||||
char *tmppath;
|
||||
int fd;
|
||||
void *map;
|
||||
size_t mapsize;
|
||||
size_t wrote;
|
||||
size_t entsize;
|
||||
size_t addralign;
|
||||
struct Elf64_Ehdr *ehdr;
|
||||
struct {
|
||||
size_t i, n;
|
||||
Elf64_Shdr *p;
|
||||
} shdrs[1];
|
||||
struct ElfWriterSyms {
|
||||
size_t i, n;
|
||||
Elf64_Sym *p;
|
||||
} syms[3][1];
|
||||
struct {
|
||||
size_t i, j, n;
|
||||
struct ElfWriterRela {
|
||||
uint64_t offset;
|
||||
struct ElfWriterSymRef {
|
||||
enum ElfWriterSymOrder {
|
||||
kElfWriterSymSection,
|
||||
kElfWriterSymLocal,
|
||||
kElfWriterSymGlobal
|
||||
} slg;
|
||||
uint32_t sym;
|
||||
} symkey;
|
||||
uint32_t type;
|
||||
int64_t addend;
|
||||
} * p;
|
||||
} relas[1];
|
||||
struct Interner *strtab;
|
||||
struct Interner *shstrtab;
|
||||
};
|
||||
|
||||
struct ElfWriter *elfwriter_open(const char *, int) nodiscard;
|
||||
void elfwriter_cargoculting(struct ElfWriter *);
|
||||
void elfwriter_close(struct ElfWriter *);
|
||||
void elfwriter_align(struct ElfWriter *, size_t, size_t);
|
||||
size_t elfwriter_startsection(struct ElfWriter *, const char *, int, int);
|
||||
void *elfwriter_reserve(struct ElfWriter *, size_t);
|
||||
void elfwriter_commit(struct ElfWriter *, size_t);
|
||||
void elfwriter_finishsection(struct ElfWriter *);
|
||||
void elfwriter_appendrela(struct ElfWriter *, uint64_t, struct ElfWriterSymRef,
|
||||
uint32_t, int64_t);
|
||||
struct ElfWriterSymRef elfwriter_linksym(struct ElfWriter *, const char *, int,
|
||||
int);
|
||||
struct ElfWriterSymRef elfwriter_appendsym(struct ElfWriter *, const char *,
|
||||
int, int, size_t, size_t);
|
||||
void elfwriter_yoink(struct ElfWriter *, const char *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_ELFWRITER_H_ */
|
31
tool/build/lib/elfwriter_cargoculting.c
Normal file
31
tool/build/lib/elfwriter_cargoculting.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*-*- 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/elf/def.h"
|
||||
#include "tool/build/lib/elfwriter.h"
|
||||
|
||||
void elfwriter_cargoculting(struct ElfWriter *elf) {
|
||||
elfwriter_startsection(elf, "", SHT_NULL, 0);
|
||||
elfwriter_startsection(elf, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
|
||||
elfwriter_finishsection(elf);
|
||||
elfwriter_startsection(elf, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
|
||||
elfwriter_finishsection(elf);
|
||||
elfwriter_startsection(elf, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
|
||||
elfwriter_finishsection(elf);
|
||||
}
|
33
tool/build/lib/elfwriter_yoink.c
Normal file
33
tool/build/lib/elfwriter_yoink.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*-*- 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/str/str.h"
|
||||
#include "tool/build/lib/elfwriter.h"
|
||||
|
||||
void elfwriter_yoink(struct ElfWriter *elf, const char *symbol) {
|
||||
unsigned char *p;
|
||||
struct ElfWriterSymRef sym;
|
||||
const unsigned char nopl[8] = "\x0f\x1f\x04\x25\x00\x00\x00\x00";
|
||||
p = elfwriter_reserve(elf, 8);
|
||||
memcpy(p, nopl, sizeof(nopl));
|
||||
sym = elfwriter_linksym(elf, symbol, ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT),
|
||||
STV_HIDDEN);
|
||||
elfwriter_appendrela(elf, sizeof(nopl) - 4, sym, R_X86_64_32, 0);
|
||||
elfwriter_commit(elf, sizeof(nopl));
|
||||
}
|
134
tool/build/lib/interner.c
Normal file
134
tool/build/lib/interner.c
Normal file
|
@ -0,0 +1,134 @@
|
|||
/*-*- 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/arraylist.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/knuthmultiplicativehash.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/interner.h"
|
||||
|
||||
#define kInitialItems 16
|
||||
|
||||
struct InternerObject {
|
||||
struct Interner pool;
|
||||
size_t i, n;
|
||||
struct InternerHash {
|
||||
unsigned hash; /* 0 means empty */
|
||||
unsigned index;
|
||||
} * p;
|
||||
};
|
||||
|
||||
static void rehash(struct InternerObject *it) {
|
||||
size_t i, j, n, step;
|
||||
struct InternerHash *p;
|
||||
n = it->n;
|
||||
p = it->p;
|
||||
it->p = xcalloc((it->n <<= 1), sizeof(struct InternerHash));
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (!p[i].hash) continue;
|
||||
step = 0;
|
||||
do {
|
||||
j = (p[i].hash + step * (step + 1) / 2) & (it->n - 1);
|
||||
step++;
|
||||
} while (it->p[j].hash);
|
||||
memcpy(&it->p[j], &p[i], sizeof(p[i]));
|
||||
}
|
||||
free_s(&p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new interner.
|
||||
*/
|
||||
struct Interner *newinterner(void) {
|
||||
struct InternerObject *it;
|
||||
it = xcalloc(1, sizeof(*it));
|
||||
it->p = xcalloc((it->n = kInitialItems), sizeof(*it->p));
|
||||
it->pool.p = xcalloc((it->pool.n = kInitialItems), sizeof(*it->pool.p));
|
||||
return &it->pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys interner.
|
||||
*/
|
||||
void freeinterner(struct Interner *t) {
|
||||
struct InternerObject *it = (struct InternerObject *)t;
|
||||
if (it) {
|
||||
free(it->pool.p);
|
||||
free(it->p);
|
||||
free(it);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of unique items interned.
|
||||
*/
|
||||
size_t interncount(const struct Interner *t) {
|
||||
struct InternerObject *it = (struct InternerObject *)t;
|
||||
return it->i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interns object.
|
||||
*
|
||||
* @return index into 𝑡→𝑝 holding equal item
|
||||
* @note use consistent size w/ non-string items
|
||||
*/
|
||||
size_t internobj(struct Interner *t, const void *data, size_t size) {
|
||||
struct InternerObject *it = (struct InternerObject *)t;
|
||||
unsigned hash;
|
||||
size_t i, step;
|
||||
unsigned char *item;
|
||||
step = 0;
|
||||
item = data;
|
||||
hash = max(1, KnuthMultiplicativeHash32(data, size));
|
||||
do {
|
||||
/* it is written that triangle probe halts iff i<n/2 && popcount(n)==1 */
|
||||
i = (hash + step * (step + 1) / 2) & (it->n - 1);
|
||||
if (it->p[i].hash == hash && it->p[i].index + size <= it->pool.n &&
|
||||
memcmp(item, &it->pool.p[it->p[i].index], size) == 0) {
|
||||
return it->p[i].index;
|
||||
}
|
||||
step++;
|
||||
} while (it->p[i].hash);
|
||||
if (++it->i == (it->n >> 1)) {
|
||||
rehash(it);
|
||||
step = 0;
|
||||
do {
|
||||
i = (hash + step * (step + 1) / 2) & (it->n - 1);
|
||||
step++;
|
||||
} while (it->p[i].hash);
|
||||
}
|
||||
it->p[i].hash = hash;
|
||||
return (it->p[i].index = concat(&it->pool, item, size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Interns string.
|
||||
*
|
||||
* The NUL-terminated string 𝑠 is concatenated to the relocatable
|
||||
* double-NUL terminated string list 𝑡→𝑝 with de-duplication and
|
||||
* preservation of insertion order.
|
||||
*
|
||||
* @return index into 𝑡→𝑝 holding string equal to 𝑠
|
||||
*/
|
||||
size_t intern(struct Interner *t, const char *s) {
|
||||
return internobj(t, s, strlen(s) + 1);
|
||||
}
|
20
tool/build/lib/interner.h
Normal file
20
tool/build/lib/interner.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_INTERNER_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_INTERNER_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct Interner {
|
||||
size_t i; /* byte size of 𝑝 */
|
||||
size_t n; /* byte capacity of 𝑝 */
|
||||
char *p; /* will relocate */
|
||||
};
|
||||
|
||||
struct Interner *newinterner(void) returnsnonnull paramsnonnull();
|
||||
void freeinterner(struct Interner *);
|
||||
size_t interncount(const struct Interner *) paramsnonnull();
|
||||
size_t internobj(struct Interner *, const void *, size_t) paramsnonnull();
|
||||
size_t intern(struct Interner *, const char *) paramsnonnull();
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_INTERNER_H_ */
|
123
tool/build/lib/persist.c
Normal file
123
tool/build/lib/persist.c
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*-*- 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/struct/iovec.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "tool/build/lib/persist.h"
|
||||
|
||||
static bool IsWithin(size_t sz1, void *vp1, size_t sz2, void *vp2) {
|
||||
char *p1 = vp1, *p2 = vp2;
|
||||
return p1 >= p2 && p1 + sz1 <= p2 + sz2;
|
||||
}
|
||||
|
||||
static bool IsOverlapping(void *vx1, void *vy1, void *vx2, void *vy2) {
|
||||
char *x1 = vx1, *y1 = vy1, *x2 = vx2, *y2 = vy2;
|
||||
return (x1 >= x2 && x1 <= y2) || (y1 >= x2 && y1 <= y2);
|
||||
}
|
||||
|
||||
static bool IsOverlappingIov(struct iovec *a, struct iovec *b) {
|
||||
char *ap = a->iov_base, *bp = b->iov_base;
|
||||
return IsOverlapping(ap, ap + a->iov_len, bp, bp + b->iov_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes struct w/ dynamic arrays to mappable file, e.g.
|
||||
*
|
||||
* PersistObject(path, 64, &(struct ObjectParam){
|
||||
* sizeof(*o), o, &o->magic, &o->abi,
|
||||
* &(struct ObjectArrayParam){
|
||||
* {&o->a1.i, sizeof(o->a1.p[0]), &o->a1.p},
|
||||
* {&o->a2.i, sizeof(o->a2.p[0]), &o->a2.p},
|
||||
* {0},
|
||||
* }});
|
||||
*
|
||||
* @param obj->magic needs to be unique for struct
|
||||
* @param obj->abi monotonically tracks breaking changes
|
||||
* @param obj->arrays needs sentinel with item size of zero
|
||||
* @note non-recursive i.e. array elements can't have pointers
|
||||
* @see MapObject()
|
||||
*/
|
||||
void PersistObject(const char *path, size_t align,
|
||||
const struct ObjectParam *obj) {
|
||||
struct iovec *iov;
|
||||
int i, n, fd, iovlen;
|
||||
const char *tmp, *pad;
|
||||
long len, size, bytes, filesize;
|
||||
unsigned char *hdr, *p1, *p2, **pp;
|
||||
intptr_t arrayptroffset, arraydataoffset;
|
||||
filesize = 0;
|
||||
DCHECK_GE(align, 1);
|
||||
CHECK_GT(*obj->magic, 0);
|
||||
CHECK_GT(*obj->abi, 0);
|
||||
CHECK(IsWithin(sizeof(*obj->magic), obj->magic, obj->size, obj->p));
|
||||
CHECK(IsWithin(sizeof(*obj->abi), obj->abi, obj->size, obj->p));
|
||||
for (n = i = 0; obj->arrays[i].size; ++i) ++n;
|
||||
iovlen = (n + 1) * 2;
|
||||
pad = gc(xcalloc(align, 1));
|
||||
hdr = gc(xmalloc(obj->size));
|
||||
iov = gc(xcalloc(iovlen, sizeof(*iov)));
|
||||
tmp = gc(xasprintf("%s.%d.%s", path, getpid(), "tmp"));
|
||||
bytes = obj->size;
|
||||
iov[0].iov_base = memcpy(hdr, obj->p, obj->size);
|
||||
iov[0].iov_len = bytes;
|
||||
iov[1].iov_base = pad;
|
||||
iov[1].iov_len = ROUNDUP(bytes, align) - bytes;
|
||||
filesize += ROUNDUP(bytes, align);
|
||||
for (i = 0; i < n; ++i) {
|
||||
pp = obj->arrays[i].pp;
|
||||
len = obj->arrays[i].len;
|
||||
size = obj->arrays[i].size;
|
||||
if (!*pp || !len) continue;
|
||||
p1 = obj->p;
|
||||
p2 = obj->arrays[i].pp;
|
||||
arrayptroffset = p2 - p1;
|
||||
arraydataoffset = filesize;
|
||||
CHECK((!len || bsrl(len) + bsrl(size) < 31),
|
||||
"path=%s i=%d len=%,lu size=%,lu", path, i, len, size);
|
||||
CHECK(IsWithin(sizeof(void *), pp, obj->size, obj->p));
|
||||
CHECK(!IsOverlapping(pp, pp + sizeof(void *), obj->magic,
|
||||
obj->magic + sizeof(*obj->magic)));
|
||||
CHECK(!IsOverlapping(pp, pp + sizeof(void *), obj->abi,
|
||||
obj->abi + sizeof(*obj->abi)));
|
||||
memcpy(hdr + arrayptroffset, &arraydataoffset, sizeof(intptr_t));
|
||||
CHECK_LT(filesize + arraydataoffset, 0x7ffff000);
|
||||
bytes = len * size;
|
||||
iov[(i + 1) * 2 + 0].iov_base = *pp;
|
||||
iov[(i + 1) * 2 + 0].iov_len = bytes;
|
||||
iov[(i + 1) * 2 + 1].iov_base = pad;
|
||||
iov[(i + 1) * 2 + 1].iov_len = ROUNDUP(bytes, align) - bytes;
|
||||
filesize += ROUNDUP(bytes, align);
|
||||
CHECK(!IsOverlappingIov(&iov[(i + 0) * 2], &iov[(i + 1) * 2]),
|
||||
"iov[%d]={%#p,%#x}, iov[%d]={%#p,%#x} path=%s", (i + 0) * 2,
|
||||
iov[(i + 0) * 2].iov_base, iov[(i + 0) * 2].iov_len, (i + 1) * 2,
|
||||
iov[(i + 1) * 2].iov_base, iov[(i + 1) * 2].iov_len, path);
|
||||
}
|
||||
CHECK_NE(-1, (fd = open(tmp, O_CREAT | O_WRONLY | O_EXCL, 0644)), "%s", tmp);
|
||||
CHECK_EQ(filesize, writev(fd, iov, iovlen));
|
||||
CHECK_NE(-1, close(fd));
|
||||
CHECK_NE(-1, rename(tmp, path), "%s", path);
|
||||
}
|
22
tool/build/lib/persist.h
Normal file
22
tool/build/lib/persist.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_PERSIST_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_PERSIST_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct ObjectParam {
|
||||
size_t size;
|
||||
void *p;
|
||||
uint32_t *magic;
|
||||
int32_t *abi;
|
||||
struct ObjectArrayParam {
|
||||
size_t len;
|
||||
size_t size;
|
||||
void *pp;
|
||||
} * arrays;
|
||||
};
|
||||
|
||||
void PersistObject(const char *, size_t, const struct ObjectParam *);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_PERSIST_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue