2020-06-15 14:18:57 +00:00
|
|
|
|
/*-*- 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 │
|
|
|
|
|
│ │
|
2020-12-28 01:18:44 +00:00
|
|
|
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
|
|
|
|
│ any purpose with or without fee is hereby granted, provided that the │
|
|
|
|
|
│ above copyright notice and this permission notice appear in all copies. │
|
2020-06-15 14:18:57 +00:00
|
|
|
|
│ │
|
2020-12-28 01:18:44 +00:00
|
|
|
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
|
|
|
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
|
|
|
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
|
|
|
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
|
|
|
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
|
|
|
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
|
|
|
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
|
|
|
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
2020-06-15 14:18:57 +00:00
|
|
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
|
|
|
#include "libc/calls/calls.h"
|
|
|
|
|
#include "libc/calls/struct/stat.h"
|
|
|
|
|
#include "libc/elf/elf.h"
|
2022-08-06 10:51:50 +00:00
|
|
|
|
#include "libc/elf/struct/shdr.h"
|
|
|
|
|
#include "libc/elf/struct/sym.h"
|
2022-08-19 17:00:41 +00:00
|
|
|
|
#include "libc/intrin/bswap.h"
|
|
|
|
|
#include "libc/intrin/safemacros.internal.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
|
#include "libc/log/check.h"
|
|
|
|
|
#include "libc/log/log.h"
|
2022-08-19 17:00:41 +00:00
|
|
|
|
#include "libc/mem/alg.h"
|
|
|
|
|
#include "libc/mem/arraylist.internal.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
|
#include "libc/mem/mem.h"
|
|
|
|
|
#include "libc/runtime/runtime.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 "third_party/getopt/getopt.h"
|
|
|
|
|
#include "third_party/xed/x86.h"
|
2022-03-16 20:33:13 +00:00
|
|
|
|
#include "tool/build/lib/getargs.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
|
#include "tool/build/lib/persist.h"
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @fileoverview Build Package Script.
|
|
|
|
|
*
|
|
|
|
|
* FIRST PURPOSE
|
|
|
|
|
*
|
|
|
|
|
* This script verifies the well-formedness of dependencies, e.g.
|
|
|
|
|
*
|
2022-03-16 20:33:13 +00:00
|
|
|
|
* o/tool/build/package.com \
|
|
|
|
|
* -o o/libc/stubs/stubs.pkg \
|
|
|
|
|
* o/libc/stubs/{a,b,...}.o
|
2020-06-15 14:18:57 +00:00
|
|
|
|
*
|
2022-03-16 20:33:13 +00:00
|
|
|
|
* o/tool/build/package.com \
|
|
|
|
|
* -o o/libc/nexgen32e/nexgen32e.pkg \
|
|
|
|
|
* -d o/libc/stubs/stubs.pkg \
|
|
|
|
|
* o/libc/nexgen32e/{a,b,...}.o
|
2020-06-15 14:18:57 +00:00
|
|
|
|
*
|
|
|
|
|
* We want the following:
|
|
|
|
|
*
|
|
|
|
|
* 1. FOO declares in FOO_DIRECTDEPS where its undefined symbols are.
|
|
|
|
|
* 2. FOO_DIRECTDEPS is complete, so FOO ∪ FOO_DIRECTDEPS has no UNDEFs.
|
|
|
|
|
* 3. FOO_DIRECTDEPS is non-transitive; thus this tool is incremental.
|
|
|
|
|
* 4. Package relationships on a whole are acyclic.
|
|
|
|
|
*
|
|
|
|
|
* These rules help keep the structure of large codebases easy to
|
|
|
|
|
* understand. More importantly, it allows us to further optimize
|
|
|
|
|
* compiled objects very cheaply as the build progresses.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define PACKAGE_MAGIC bswap_32(0xBEEFBEEFu)
|
|
|
|
|
#define PACKAGE_ABI 1
|
|
|
|
|
|
|
|
|
|
struct Packages {
|
|
|
|
|
size_t i, n;
|
|
|
|
|
struct Package {
|
|
|
|
|
uint32_t magic;
|
|
|
|
|
int32_t abi;
|
2020-11-09 23:41:11 +00:00
|
|
|
|
uint32_t path; // pkg->strings.p[path]
|
|
|
|
|
int64_t fd; // not persisted
|
|
|
|
|
void *addr; // not persisted
|
|
|
|
|
size_t size; // not persisted
|
2020-06-15 14:18:57 +00:00
|
|
|
|
struct Strings {
|
|
|
|
|
size_t i, n;
|
2020-11-09 23:41:11 +00:00
|
|
|
|
char *p; // persisted as pkg+RVA
|
|
|
|
|
} strings; // TODO(jart): interning?
|
2020-06-15 14:18:57 +00:00
|
|
|
|
struct Objects {
|
|
|
|
|
size_t i, n;
|
|
|
|
|
struct Object {
|
2020-11-09 23:41:11 +00:00
|
|
|
|
uint32_t path; // pkg->strings.p[path]
|
|
|
|
|
unsigned mode; // not persisted
|
|
|
|
|
struct Elf64_Ehdr *elf; // not persisted
|
|
|
|
|
size_t size; // not persisted
|
|
|
|
|
char *strs; // not persisted
|
|
|
|
|
Elf64_Sym *syms; // not persisted
|
|
|
|
|
Elf64_Xword symcount; // not persisted
|
2020-06-15 14:18:57 +00:00
|
|
|
|
struct Sections {
|
|
|
|
|
size_t i, n;
|
|
|
|
|
struct Section {
|
|
|
|
|
enum SectionKind {
|
|
|
|
|
kUndef,
|
|
|
|
|
kText,
|
|
|
|
|
kData,
|
|
|
|
|
kPiroRelo,
|
|
|
|
|
kPiroData,
|
|
|
|
|
kPiroBss,
|
|
|
|
|
kBss,
|
|
|
|
|
} kind;
|
|
|
|
|
} * p;
|
2020-11-09 23:41:11 +00:00
|
|
|
|
} sections; // not persisted
|
|
|
|
|
} * p; // persisted as pkg+RVA
|
2020-06-15 14:18:57 +00:00
|
|
|
|
} objects;
|
|
|
|
|
struct Symbols {
|
|
|
|
|
size_t i, n;
|
|
|
|
|
struct Symbol {
|
2020-11-09 23:41:11 +00:00
|
|
|
|
uint32_t name; // pkg->strings.p[name]
|
2020-06-15 14:18:57 +00:00
|
|
|
|
enum SectionKind kind : 8;
|
2022-04-21 16:15:36 +00:00
|
|
|
|
uint8_t bind_ : 4;
|
2020-06-15 14:18:57 +00:00
|
|
|
|
uint8_t type : 4;
|
2020-11-09 23:41:11 +00:00
|
|
|
|
uint16_t object; // pkg->objects.p[object]
|
|
|
|
|
} * p; // persisted as pkg+RVA
|
|
|
|
|
} symbols, undefs; // TODO(jart): hash undefs?
|
|
|
|
|
} * *p; // persisted across multiple files
|
2020-06-15 14:18:57 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int CompareSymbolName(const struct Symbol *a, const struct Symbol *b,
|
2021-04-18 18:34:59 +00:00
|
|
|
|
const char *tab) {
|
|
|
|
|
return strcmp(tab + a->name, tab + b->name);
|
2020-06-15 14:18:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct Package *LoadPackage(const char *path) {
|
|
|
|
|
int fd;
|
|
|
|
|
ssize_t i;
|
|
|
|
|
struct stat st;
|
|
|
|
|
struct Package *pkg;
|
|
|
|
|
CHECK(fileexists(path), "%s: %s: %s\n", "error", path, "not found");
|
|
|
|
|
CHECK_NE(-1, (fd = open(path, O_RDONLY)), "%s", path);
|
|
|
|
|
CHECK_NE(-1, fstat(fd, &st));
|
2022-08-19 17:00:41 +00:00
|
|
|
|
CHECK_NE(MAP_FAILED,
|
|
|
|
|
(pkg = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
|
|
|
|
|
fd, 0)),
|
|
|
|
|
"path=%s", path);
|
2020-06-15 14:18:57 +00:00
|
|
|
|
CHECK_NE(-1, close(fd));
|
|
|
|
|
CHECK_EQ(PACKAGE_MAGIC, pkg->magic, "corrupt package: %`'s", path);
|
|
|
|
|
pkg->strings.p = (char *)((intptr_t)pkg->strings.p + (intptr_t)pkg);
|
|
|
|
|
pkg->objects.p = (struct Object *)((intptr_t)pkg->objects.p + (intptr_t)pkg);
|
|
|
|
|
pkg->symbols.p = (struct Symbol *)((intptr_t)pkg->symbols.p + (intptr_t)pkg);
|
|
|
|
|
pkg->addr = pkg;
|
|
|
|
|
pkg->size = st.st_size;
|
2021-04-18 18:34:59 +00:00
|
|
|
|
CHECK_NE(-1, mprotect(pkg, st.st_size, PROT_READ));
|
2020-06-15 14:18:57 +00:00
|
|
|
|
return pkg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AddDependency(struct Packages *deps, const char *path) {
|
|
|
|
|
struct Package *pkg;
|
|
|
|
|
pkg = LoadPackage(path);
|
|
|
|
|
CHECK_NE(-1, append(deps, &pkg));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WritePackage(struct Package *pkg) {
|
|
|
|
|
CHECK_NE(0, PACKAGE_MAGIC);
|
|
|
|
|
pkg->magic = PACKAGE_MAGIC;
|
|
|
|
|
pkg->abi = PACKAGE_ABI;
|
|
|
|
|
DEBUGF("%s has %,ld objects, %,ld symbols, and a %,ld byte string table",
|
|
|
|
|
&pkg->strings.p[pkg->path], pkg->objects.i, pkg->symbols.i,
|
|
|
|
|
pkg->strings.i);
|
|
|
|
|
PersistObject(
|
|
|
|
|
&pkg->strings.p[pkg->path], 64,
|
|
|
|
|
&(struct ObjectParam){
|
|
|
|
|
sizeof(struct Package),
|
|
|
|
|
pkg,
|
|
|
|
|
&pkg->magic,
|
|
|
|
|
&pkg->abi,
|
|
|
|
|
(struct ObjectArrayParam[]){
|
|
|
|
|
{pkg->strings.i, sizeof(pkg->strings.p[0]), &pkg->strings.p},
|
|
|
|
|
{pkg->objects.i, sizeof(pkg->objects.p[0]), &pkg->objects.p},
|
|
|
|
|
{pkg->symbols.i, sizeof(pkg->symbols.p[0]), &pkg->symbols.p},
|
|
|
|
|
{0},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GetOpts(struct Package *pkg, struct Packages *deps, int argc,
|
|
|
|
|
char *argv[]) {
|
|
|
|
|
long i, si, opt;
|
2022-03-16 20:33:13 +00:00
|
|
|
|
const char *arg;
|
|
|
|
|
struct GetArgs ga;
|
2020-06-15 14:18:57 +00:00
|
|
|
|
pkg->path = -1;
|
|
|
|
|
while ((opt = getopt(argc, argv, "vho:d:")) != -1) {
|
|
|
|
|
switch (opt) {
|
|
|
|
|
case 'v':
|
2021-03-01 07:42:35 +00:00
|
|
|
|
__log_level = kLogDebug;
|
2020-06-15 14:18:57 +00:00
|
|
|
|
break;
|
|
|
|
|
case 'o':
|
|
|
|
|
pkg->path = concat(&pkg->strings, optarg, strlen(optarg) + 1);
|
|
|
|
|
break;
|
|
|
|
|
case 'd':
|
|
|
|
|
AddDependency(deps, optarg);
|
|
|
|
|
break;
|
2021-01-16 20:05:41 +00:00
|
|
|
|
case 'h':
|
|
|
|
|
exit(0);
|
2020-06-15 14:18:57 +00:00
|
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "%s: %s [%s %s] [%s %s] %s\n", "Usage",
|
|
|
|
|
program_invocation_name, "-o", "OUTPACKAGE", "-d", "DEPPACKAGE",
|
|
|
|
|
"OBJECT...");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-08-25 11:23:25 +00:00
|
|
|
|
CHECK_NE(-1, pkg->path, "no packages passed to package.com");
|
2020-06-15 14:18:57 +00:00
|
|
|
|
CHECK_LT(optind, argc,
|
|
|
|
|
"no objects passed to package.com; "
|
|
|
|
|
"is your foo.mk $(FOO_OBJS) glob broken?");
|
2022-03-16 20:33:13 +00:00
|
|
|
|
getargs_init(&ga, argv + optind);
|
|
|
|
|
while ((arg = getargs_next(&ga))) {
|
|
|
|
|
CHECK_NE(-1, (si = concat(&pkg->strings, arg, strlen(arg) + 1)));
|
2020-06-15 14:18:57 +00:00
|
|
|
|
CHECK_NE(-1, append(&pkg->objects, (&(struct Object){si})));
|
|
|
|
|
}
|
2022-03-16 20:33:13 +00:00
|
|
|
|
getargs_destroy(&ga);
|
2020-06-15 14:18:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IndexSections(struct Object *obj) {
|
|
|
|
|
size_t i;
|
|
|
|
|
const char *name;
|
|
|
|
|
const uint8_t *code;
|
|
|
|
|
struct Section sect;
|
|
|
|
|
const Elf64_Shdr *shdr;
|
|
|
|
|
struct XedDecodedInst xedd;
|
|
|
|
|
for (i = 0; i < obj->elf->e_shnum; ++i) {
|
2021-09-28 05:58:51 +00:00
|
|
|
|
bzero(§, sizeof(sect));
|
2020-11-25 16:19:00 +00:00
|
|
|
|
CHECK_NOTNULL((shdr = GetElfSectionHeaderAddress(obj->elf, obj->size, i)));
|
2020-06-15 14:18:57 +00:00
|
|
|
|
if (shdr->sh_type != SHT_NULL) {
|
2020-11-09 23:41:11 +00:00
|
|
|
|
CHECK_NOTNULL((name = GetElfSectionName(obj->elf, obj->size, shdr)));
|
2022-09-13 06:10:38 +00:00
|
|
|
|
if (_startswith(name, ".sort.")) name += 5;
|
2020-06-15 14:18:57 +00:00
|
|
|
|
if ((strcmp(name, ".piro.relo") == 0 ||
|
2022-09-13 06:10:38 +00:00
|
|
|
|
_startswith(name, ".piro.relo.")) ||
|
2020-06-15 14:18:57 +00:00
|
|
|
|
(strcmp(name, ".data.rel.ro") == 0 ||
|
2022-09-13 06:10:38 +00:00
|
|
|
|
_startswith(name, ".data.rel.ro."))) {
|
2020-06-15 14:18:57 +00:00
|
|
|
|
sect.kind = kPiroRelo;
|
|
|
|
|
} else if (strcmp(name, ".piro.data") == 0 ||
|
2022-09-13 06:10:38 +00:00
|
|
|
|
_startswith(name, ".piro.data.")) {
|
2020-06-15 14:18:57 +00:00
|
|
|
|
sect.kind = kPiroData;
|
|
|
|
|
} else if (strcmp(name, ".piro.bss") == 0 ||
|
2022-09-13 06:10:38 +00:00
|
|
|
|
_startswith(name, ".piro.bss.")) {
|
2020-06-15 14:18:57 +00:00
|
|
|
|
sect.kind = kPiroBss;
|
2022-09-13 06:10:38 +00:00
|
|
|
|
} else if (strcmp(name, ".data") == 0 || _startswith(name, ".data.")) {
|
2020-06-15 14:18:57 +00:00
|
|
|
|
sect.kind = kData;
|
2022-09-13 06:10:38 +00:00
|
|
|
|
} else if (strcmp(name, ".bss") == 0 || _startswith(name, ".bss.")) {
|
2020-06-15 14:18:57 +00:00
|
|
|
|
sect.kind = kBss;
|
|
|
|
|
} else {
|
|
|
|
|
sect.kind = kText;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
sect.kind = kUndef; /* should always and only be section #0 */
|
|
|
|
|
}
|
|
|
|
|
CHECK_NE(-1, append(&obj->sections, §));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum SectionKind ClassifySection(struct Object *obj, uint8_t type,
|
|
|
|
|
Elf64_Section shndx) {
|
|
|
|
|
if (type == STT_COMMON) return kBss;
|
|
|
|
|
if (!obj->sections.i) return kText;
|
|
|
|
|
return obj->sections.p[min(max(0, shndx), obj->sections.i - 1)].kind;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LoadSymbols(struct Package *pkg, uint32_t object) {
|
|
|
|
|
Elf64_Xword i;
|
|
|
|
|
const char *name;
|
|
|
|
|
struct Object *obj;
|
|
|
|
|
struct Symbol symbol;
|
|
|
|
|
obj = &pkg->objects.p[object];
|
|
|
|
|
symbol.object = object;
|
|
|
|
|
for (i = 0; i < obj->symcount; ++i) {
|
2022-04-21 16:15:36 +00:00
|
|
|
|
symbol.bind_ = ELF64_ST_BIND(obj->syms[i].st_info);
|
2020-06-15 14:18:57 +00:00
|
|
|
|
symbol.type = ELF64_ST_TYPE(obj->syms[i].st_info);
|
2022-04-21 16:15:36 +00:00
|
|
|
|
if (symbol.bind_ != STB_LOCAL &&
|
2020-06-15 14:18:57 +00:00
|
|
|
|
(symbol.type == STT_OBJECT || symbol.type == STT_FUNC ||
|
|
|
|
|
symbol.type == STT_COMMON || symbol.type == STT_NOTYPE)) {
|
2020-11-09 23:41:11 +00:00
|
|
|
|
name = GetElfString(obj->elf, obj->size, obj->strs, obj->syms[i].st_name);
|
2020-06-15 14:18:57 +00:00
|
|
|
|
DEBUGF("%s", name);
|
|
|
|
|
if (strcmp(name, "_GLOBAL_OFFSET_TABLE_") != 0) {
|
|
|
|
|
symbol.kind = ClassifySection(obj, symbol.type, obj->syms[i].st_shndx);
|
|
|
|
|
CHECK_NE(-1,
|
|
|
|
|
(symbol.name = concat(&pkg->strings, name, strlen(name) + 1)));
|
|
|
|
|
CHECK_NE(-1,
|
|
|
|
|
append(symbol.kind != kUndef ? &pkg->symbols : &pkg->undefs,
|
|
|
|
|
&symbol));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OpenObject(struct Package *pkg, struct Object *obj, int mode, int prot,
|
|
|
|
|
int flags) {
|
|
|
|
|
int fd;
|
|
|
|
|
struct stat st;
|
2020-11-09 23:41:11 +00:00
|
|
|
|
CHECK_NE(-1, (fd = open(&pkg->strings.p[obj->path], (obj->mode = mode))),
|
|
|
|
|
"path=%`'s", &pkg->strings.p[obj->path]);
|
2020-06-15 14:18:57 +00:00
|
|
|
|
CHECK_NE(-1, fstat(fd, &st));
|
2021-02-20 20:39:39 +00:00
|
|
|
|
CHECK_NE(
|
|
|
|
|
MAP_FAILED,
|
|
|
|
|
(obj->elf = mmap(NULL, (obj->size = st.st_size), prot, flags, fd, 0)),
|
|
|
|
|
"path=%`'s", &pkg->strings.p[obj->path]);
|
2020-06-15 14:18:57 +00:00
|
|
|
|
CHECK_NE(-1, close(fd));
|
2020-11-09 23:41:11 +00:00
|
|
|
|
CHECK(IsElf64Binary(obj->elf, obj->size), "path=%`'s",
|
2020-09-28 08:13:56 +00:00
|
|
|
|
&pkg->strings.p[obj->path]);
|
2021-02-08 17:19:00 +00:00
|
|
|
|
CHECK_NOTNULL((obj->strs = GetElfStringTable(obj->elf, obj->size)), "on %s",
|
|
|
|
|
&pkg->strings.p[obj->path]);
|
2020-06-15 14:18:57 +00:00
|
|
|
|
CHECK_NOTNULL(
|
2020-11-09 23:41:11 +00:00
|
|
|
|
(obj->syms = GetElfSymbolTable(obj->elf, obj->size, &obj->symcount)));
|
2020-06-15 14:18:57 +00:00
|
|
|
|
CHECK_NE(0, obj->symcount);
|
|
|
|
|
IndexSections(obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CloseObject(struct Object *obj) {
|
|
|
|
|
CHECK_NE(-1, munmap(obj->elf, obj->size));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LoadObjects(struct Package *pkg) {
|
|
|
|
|
size_t i;
|
|
|
|
|
struct Object *obj;
|
|
|
|
|
for (i = 0; i < pkg->objects.i; ++i) {
|
2021-04-18 18:34:59 +00:00
|
|
|
|
obj = pkg->objects.p + i;
|
2020-06-15 14:18:57 +00:00
|
|
|
|
OpenObject(pkg, obj, O_RDONLY, PROT_READ, MAP_SHARED);
|
|
|
|
|
LoadSymbols(pkg, i);
|
|
|
|
|
CloseObject(obj);
|
|
|
|
|
}
|
2021-04-18 18:34:59 +00:00
|
|
|
|
qsort_r(pkg->symbols.p, pkg->symbols.i, sizeof(*pkg->symbols.p),
|
|
|
|
|
(void *)CompareSymbolName, pkg->strings.p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct Symbol *BisectSymbol(struct Package *pkg, const char *name) {
|
|
|
|
|
int c;
|
|
|
|
|
long m, l, r;
|
|
|
|
|
l = 0;
|
|
|
|
|
r = pkg->symbols.i - 1;
|
|
|
|
|
while (l <= r) {
|
|
|
|
|
m = (l + r) >> 1;
|
|
|
|
|
c = strcmp(pkg->strings.p + pkg->symbols.p[m].name, name);
|
|
|
|
|
if (c < 0) {
|
|
|
|
|
l = m + 1;
|
|
|
|
|
} else if (c > 0) {
|
|
|
|
|
r = m - 1;
|
|
|
|
|
} else {
|
|
|
|
|
return pkg->symbols.p + m;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
2020-06-15 14:18:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FindSymbol(const char *name, struct Package *pkg,
|
|
|
|
|
struct Packages *directdeps, struct Package **out_pkg,
|
|
|
|
|
struct Symbol **out_sym) {
|
2021-04-18 18:34:59 +00:00
|
|
|
|
size_t i, j;
|
|
|
|
|
struct Symbol *sym;
|
|
|
|
|
if ((sym = BisectSymbol(pkg, name))) {
|
2020-06-15 14:18:57 +00:00
|
|
|
|
if (out_sym) *out_sym = sym;
|
2021-04-18 18:34:59 +00:00
|
|
|
|
if (out_pkg) *out_pkg = pkg;
|
2020-06-15 14:18:57 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < directdeps->i; ++i) {
|
2021-04-18 18:34:59 +00:00
|
|
|
|
if ((sym = BisectSymbol(directdeps->p[i], name))) {
|
2020-06-15 14:18:57 +00:00
|
|
|
|
if (out_sym) *out_sym = sym;
|
2021-04-18 18:34:59 +00:00
|
|
|
|
if (out_pkg) *out_pkg = directdeps->p[i];
|
2020-06-15 14:18:57 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CheckStrictDeps(struct Package *pkg, struct Packages *deps) {
|
|
|
|
|
size_t i, j;
|
|
|
|
|
struct Package *dep;
|
|
|
|
|
struct Symbol *undef;
|
|
|
|
|
for (i = 0; i < pkg->undefs.i; ++i) {
|
|
|
|
|
undef = &pkg->undefs.p[i];
|
2022-04-21 16:15:36 +00:00
|
|
|
|
if (undef->bind_ == STB_WEAK) continue;
|
2021-04-18 18:34:59 +00:00
|
|
|
|
if (!FindSymbol(pkg->strings.p + undef->name, pkg, deps, NULL, NULL)) {
|
|
|
|
|
fprintf(stderr, "%s: %`'s (%s) %s %s\n", "error",
|
|
|
|
|
pkg->strings.p + undef->name,
|
|
|
|
|
pkg->strings.p + pkg->objects.p[undef->object].path,
|
|
|
|
|
"not defined by direct deps of", pkg->strings.p + pkg->path);
|
2020-06-15 14:18:57 +00:00
|
|
|
|
for (j = 0; j < deps->i; ++j) {
|
|
|
|
|
dep = deps->p[j];
|
|
|
|
|
fputc('\t', stderr);
|
2021-04-18 18:34:59 +00:00
|
|
|
|
fputs(dep->strings.p + dep->path, stderr);
|
2020-06-15 14:18:57 +00:00
|
|
|
|
fputc('\n', stderr);
|
|
|
|
|
}
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
free(pkg->undefs.p);
|
2021-09-28 05:58:51 +00:00
|
|
|
|
bzero(&pkg->undefs, sizeof(pkg->undefs));
|
2020-06-15 14:18:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
forceinline bool IsRipRelativeModrm(uint8_t modrm) {
|
|
|
|
|
return (modrm & 0b11000111) == 0b00000101;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
forceinline uint8_t ChangeRipToRbx(uint8_t modrm) {
|
|
|
|
|
return (modrm & 0b00111000) | 0b10000011;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IsSymbolDirectlyReachable(struct Package *pkg, struct Packages *deps,
|
|
|
|
|
const char *symbol) {
|
|
|
|
|
return FindSymbol(symbol, pkg, deps, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Package(int argc, char *argv[], struct Package *pkg,
|
|
|
|
|
struct Packages *deps) {
|
|
|
|
|
size_t i, j;
|
|
|
|
|
GetOpts(pkg, deps, argc, argv);
|
|
|
|
|
LoadObjects(pkg);
|
|
|
|
|
CheckStrictDeps(pkg, deps);
|
|
|
|
|
WritePackage(pkg);
|
|
|
|
|
for (i = 0; i < deps->i; ++i) {
|
|
|
|
|
CHECK_NE(-1, munmap(deps->p[i]->addr, deps->p[i]->size));
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < pkg->objects.i; ++i) {
|
|
|
|
|
free(pkg->objects.p[i].sections.p);
|
|
|
|
|
}
|
2022-03-16 20:33:13 +00:00
|
|
|
|
free(pkg->strings.p);
|
|
|
|
|
free(pkg->objects.p);
|
|
|
|
|
free(pkg->symbols.p);
|
|
|
|
|
free(deps->p);
|
2020-06-15 14:18:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
|
struct Package pkg;
|
|
|
|
|
struct Packages deps;
|
2021-08-12 07:42:14 +00:00
|
|
|
|
if (argc == 2 && !strcmp(argv[1], "-n")) exit(0);
|
2022-03-16 20:33:13 +00:00
|
|
|
|
if (IsModeDbg()) ShowCrashReports();
|
2021-09-28 05:58:51 +00:00
|
|
|
|
bzero(&pkg, sizeof(pkg));
|
|
|
|
|
bzero(&deps, sizeof(deps));
|
2020-06-15 14:18:57 +00:00
|
|
|
|
Package(argc, argv, &pkg, &deps);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|