mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-01 23:40:28 +00:00
Redesign cosmocc
toolchain
The `cosmocc` compiler is now being distributed as a self-contained toolchain that's path-agnostic and it no longer requires you clone the Cosmop repo to use it. The bin/ folder has been deleted from the mono repo. The `fatcosmocc` command has been renamed to `cosmocc`. MacOS support now works very well.
This commit is contained in:
parent
3802428026
commit
291103ad8d
71 changed files with 2437 additions and 1398 deletions
|
@ -35,6 +35,7 @@
|
|||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdckdint.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/msync.h"
|
||||
|
@ -51,17 +52,6 @@
|
|||
#define MRS_TPIDR_EL0 0xd53bd040u
|
||||
#define MOV_REG(DST, SRC) (0xaa0003e0u | (SRC) << 16 | (DST))
|
||||
|
||||
const unsigned char kFatNops[8][8] = {
|
||||
{}, //
|
||||
{0x90}, // nop
|
||||
{0x66, 0x90}, // xchg %ax,%ax
|
||||
{0x0f, 0x1f, 0x00}, // nopl (%rax)
|
||||
{0x0f, 0x1f, 0x40, 0x00}, // nopl 0x00(%rax)
|
||||
{0x0f, 0x1f, 0x44, 0x00, 0x00}, // nopl 0x00(%rax,%rax,1)
|
||||
{0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00}, // nopw 0x00(%rax,%rax,1)
|
||||
{0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00}, // nopl 0x00000000(%rax)
|
||||
};
|
||||
|
||||
static int mode;
|
||||
static int fildes;
|
||||
static char *symstrs;
|
||||
|
@ -138,6 +128,70 @@ static void GetOpts(int argc, char *argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
// Official Intel Multibyte No-Operation Instructions. See
|
||||
// Intel's Six Thousand Page Manual, Volume 2, Table 4-12:
|
||||
// On "Recommended Multi-Byte Sequence of NOP Instruction"
|
||||
static const unsigned char kNops[10][10] = {
|
||||
{}, //
|
||||
{/***/ /***/ 0x90}, // nop
|
||||
{0x66, /***/ 0x90}, // xchg %ax,%ax
|
||||
{/***/ 0x0f, 0x1f, 0000}, // nopl (%rax)
|
||||
{/***/ 0x0f, 0x1f, 0100, /***/ 0}, // nopl 0x00(%rax)
|
||||
{/***/ 0x0f, 0x1f, 0104, 0000, 0}, // nopl 0x00(%rax,%rax,1)
|
||||
{0x66, 0x0f, 0x1f, 0104, 0000, 0}, // nopw 0x00(%rax,%rax,1)
|
||||
{/***/ 0x0f, 0x1f, 0200, 0000, 0, 0, 0}, // nopl 0x00000000(%rax)
|
||||
{/***/ 0x0F, 0x1F, 0204, 0000, 0, 0, 0, 0}, // nopl 0x00000000(%rax,%rax,1)
|
||||
{0x66, 0x0F, 0x1F, 0204, 0000, 0, 0, 0, 0}, // nopw 0x00000000(%rax,%rax,1)
|
||||
// osz map op modrm sib displacement //
|
||||
};
|
||||
|
||||
/**
|
||||
* Rewrites leading NOP instructions to have fewer instructions.
|
||||
*
|
||||
* For example, the following code:
|
||||
*
|
||||
* nop
|
||||
* nop
|
||||
* nop
|
||||
* nop
|
||||
* nop
|
||||
* nop
|
||||
* nop
|
||||
* nop
|
||||
* nop
|
||||
* nop
|
||||
* nop
|
||||
* nop
|
||||
* ret
|
||||
* nop
|
||||
* nop
|
||||
*
|
||||
* Would be morphed into the following:
|
||||
*
|
||||
* nopw 0x00000000(%rax,%rax,1)
|
||||
* xchg %ax,%ax
|
||||
* ret
|
||||
* nop
|
||||
* nop
|
||||
*
|
||||
* @param p points to memory region that shall be modified
|
||||
* @param e points to end of memory region, i.e. `p + #bytes`
|
||||
* @return p advanced past last morphed byte
|
||||
*/
|
||||
static unsigned char *CoalesceNops(unsigned char *p, const unsigned char *e) {
|
||||
long n;
|
||||
for (; p + 1 < e; p += n) {
|
||||
if (p[0] != 0x90) break;
|
||||
if (p[1] != 0x90) break;
|
||||
for (n = 2; p + n < e; ++n) {
|
||||
if (p[n] != 0x90) break;
|
||||
if (n == ARRAYLEN(kNops) - 1) break;
|
||||
}
|
||||
memcpy(p, kNops[n], n);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static void CheckPrivilegedCrossReferences(void) {
|
||||
unsigned long x;
|
||||
const char *secname;
|
||||
|
@ -202,40 +256,32 @@ static void RewriteTlsCode(void) {
|
|||
* `STT_FUNC` and `st_size` must have the function's byte length.
|
||||
*/
|
||||
static void OptimizePatchableFunctionEntries(void) {
|
||||
#ifdef __x86_64__
|
||||
long i, n;
|
||||
long i;
|
||||
Elf64_Shdr *shdr;
|
||||
unsigned char *p, *pe;
|
||||
for (i = 0; i < symcount; ++i) {
|
||||
if (!syms[i].st_size) continue;
|
||||
if (ELF64_ST_TYPE(syms[i].st_info) != STT_FUNC) continue;
|
||||
if (!(shdr = GetElfSectionHeaderAddress(elf, esize, syms[i].st_shndx))) {
|
||||
Die("elf header overflow #3");
|
||||
}
|
||||
if (shdr->sh_type != SHT_PROGBITS) continue;
|
||||
if (!(p = GetElfSectionAddress(elf, esize, shdr))) {
|
||||
Die("elf header overflow #4");
|
||||
}
|
||||
if (syms[i].st_value < shdr->sh_addr) {
|
||||
Die("elf symbol beneath section");
|
||||
}
|
||||
if ((syms[i].st_value - shdr->sh_addr > esize ||
|
||||
(p += syms[i].st_value - shdr->sh_addr) >=
|
||||
(unsigned char *)elf + esize) ||
|
||||
(syms[i].st_size >= esize ||
|
||||
(pe = p + syms[i].st_size) >= (unsigned char *)elf + esize)) {
|
||||
Die("elf symbol overflow");
|
||||
};
|
||||
for (; p + 1 < pe; p += n) {
|
||||
if (p[0] != 0x90) break;
|
||||
if (p[1] != 0x90) break;
|
||||
for (n = 2; p + n < pe && n < ARRAYLEN(kFatNops); ++n) {
|
||||
if (p[n] != 0x90) break;
|
||||
unsigned char *p;
|
||||
Elf64_Addr sym_rva;
|
||||
if (elf->e_machine == EM_NEXGEN32E) {
|
||||
for (i = 0; i < symcount; ++i) {
|
||||
if (!syms[i].st_size) continue;
|
||||
if (ELF64_ST_TYPE(syms[i].st_info) != STT_FUNC) continue;
|
||||
if (!(shdr = GetElfSectionHeaderAddress(elf, esize, syms[i].st_shndx))) {
|
||||
Die("elf header overflow #3");
|
||||
}
|
||||
memcpy(p, kFatNops[n], n);
|
||||
if (shdr->sh_type != SHT_PROGBITS) continue;
|
||||
if (!(p = GetElfSectionAddress(elf, esize, shdr))) {
|
||||
Die("elf section overflow");
|
||||
}
|
||||
if (ckd_sub(&sym_rva, syms[i].st_value, shdr->sh_addr)) {
|
||||
Die("elf symbol beneath section");
|
||||
}
|
||||
if (sym_rva > esize - shdr->sh_offset || //
|
||||
(p += sym_rva) >= (unsigned char *)elf + esize || //
|
||||
syms[i].st_size >= esize - sym_rva) {
|
||||
Die("elf symbol overflow");
|
||||
}
|
||||
CoalesceNops(p, p + syms[i].st_size);
|
||||
}
|
||||
}
|
||||
#endif /* __x86_64__ */
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,15 +16,8 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "ape/relocations.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/mem/arraylist2.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/append.h"
|
||||
|
@ -44,13 +37,38 @@ struct Visited {
|
|||
};
|
||||
|
||||
char *output;
|
||||
const char *prog;
|
||||
struct Interner *visited;
|
||||
|
||||
void Visit(const char *);
|
||||
|
||||
static wontreturn void Die(const char *reason) {
|
||||
tinyprint(2, prog, ": ", reason, "\n", NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static wontreturn void DieSys(const char *thing) {
|
||||
perror(thing);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static wontreturn void DieOom(void) {
|
||||
Die("out of memory");
|
||||
}
|
||||
|
||||
static void Appends(char **b, const char *s) {
|
||||
if (appends(b, s) == -1) DieOom();
|
||||
}
|
||||
|
||||
static void Appendd(char **b, const void *p, size_t n) {
|
||||
if (appendd(b, p, n) == -1) DieOom();
|
||||
}
|
||||
|
||||
size_t GetFdSize(int fd) {
|
||||
struct stat st;
|
||||
CHECK_NE(-1, fstat(fd, &st));
|
||||
if (fstat(fd, &st)) {
|
||||
DieSys("fstat");
|
||||
}
|
||||
return st.st_size;
|
||||
}
|
||||
|
||||
|
@ -84,12 +102,11 @@ void Process(const char *p, const char *pe, const char *path, bool isheader) {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
appendd(&output, p, p2 - p);
|
||||
Appendd(&output, p, p2 - p);
|
||||
}
|
||||
if (noformat) {
|
||||
appends(&output, "/* clang-format on */\n");
|
||||
Appends(&output, "/* clang-format on */\n");
|
||||
}
|
||||
kprintf("finished%n");
|
||||
}
|
||||
|
||||
void Visit(const char *path) {
|
||||
|
@ -105,55 +122,40 @@ void Visit(const char *path) {
|
|||
if (startswith(path, "libc/isystem/")) return;
|
||||
isheader = endswith(path, ".h");
|
||||
if (isheader && isinterned(visited, path)) return;
|
||||
appends(&output, "\n\f\n/*!BEGIN ");
|
||||
appends(&output, path);
|
||||
appends(&output, " */\n\n");
|
||||
Appends(&output, "\n\f\n/*!BEGIN ");
|
||||
Appends(&output, path);
|
||||
Appends(&output, " */\n\n");
|
||||
intern(visited, path);
|
||||
if ((fd = open(path, O_RDONLY)) == -1) {
|
||||
fprintf(stderr, "error: %s: failed to open\n", path);
|
||||
exit(1);
|
||||
}
|
||||
if ((fd = open(path, O_RDONLY)) == -1) DieSys(path);
|
||||
if ((size = GetFdSize(fd))) {
|
||||
kprintf("size 1 = %'zu%n", size);
|
||||
CHECK_NE(MAP_FAILED,
|
||||
(map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0)));
|
||||
map = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (map == MAP_FAILED) DieSys(path);
|
||||
Process(map, map + size, path, isheader);
|
||||
kprintf("size = %'zu%n", size);
|
||||
CHECK_EQ(0, munmap(map, size), "p=%p z=%'zu path=%s", map, size, path);
|
||||
if (munmap(map, size)) DieSys(path);
|
||||
}
|
||||
CHECK_EQ(0, close(fd));
|
||||
}
|
||||
|
||||
ssize_t WriteAll(int fd, const char *p, size_t n) {
|
||||
ssize_t rc;
|
||||
size_t i, got;
|
||||
for (i = 0; i < n;) {
|
||||
rc = write(fd, p + i, n - i);
|
||||
if (rc != -1) {
|
||||
got = rc;
|
||||
i += got;
|
||||
} else if (errno != EINTR) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
if (close(fd)) DieSys(path);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
size_t bytes;
|
||||
const char *src;
|
||||
struct GetArgs ga;
|
||||
ShowCrashReports();
|
||||
prog = argv[0];
|
||||
if (!prog) prog = "rollup";
|
||||
visited = newinterner();
|
||||
appends(&output, "#ifndef COSMOPOLITAN_H_\n");
|
||||
appends(&output, "#define COSMOPOLITAN_H_\n");
|
||||
Appends(&output, "#ifndef COSMOPOLITAN_H_\n");
|
||||
Appends(&output, "#define COSMOPOLITAN_H_\n");
|
||||
getargs_init(&ga, argv + 1);
|
||||
while ((src = getargs_next(&ga))) {
|
||||
Visit(src);
|
||||
}
|
||||
getargs_destroy(&ga);
|
||||
appends(&output, "\n");
|
||||
appends(&output, "#endif /* COSMOPOLITAN_H_ */\n");
|
||||
CHECK_NE(-1, WriteAll(1, output, appendz(output).i));
|
||||
Appends(&output, "\n");
|
||||
Appends(&output, "#endif /* COSMOPOLITAN_H_ */\n");
|
||||
bytes = appendz(output).i;
|
||||
if (write(1, output, bytes) != bytes) {
|
||||
DieSys(prog);
|
||||
}
|
||||
freeinterner(visited);
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue