diff options
| -rw-r--r-- | c/lex.c | 18 | ||||
| -rw-r--r-- | common.h | 8 | ||||
| -rw-r--r-- | hostconfig.h | 27 | ||||
| -rw-r--r-- | io.c | 2 | ||||
| -rw-r--r-- | main.c | 108 | ||||
| -rw-r--r-- | obj/elf.c | 7 | ||||
| -rw-r--r-- | targ.c | 57 |
7 files changed, 195 insertions, 32 deletions
@@ -1963,7 +1963,6 @@ addpredefmacros(struct arena **tmparena) { "__has_builtin", { .predef = 1, .nparam = 1, .fnlike = 1, .special = 1, .handlerfn = mac__has_builtin }}, { "__STDC__", { .predef = 1, .rlist = { &tok_1, 1 } }}, { "__STDC_VERSION__", { .predef = 1, .rlist = { &tok_ver, 1 } }}, - { "__STDC_HOSTED__", { .predef = 1, .rlist = { &tok_1, 1 } }}, { "__antcc__", { .predef = 1, .rlist = { &tok_1, 1 } }}, }; switch (ccopt.cstd) { @@ -1978,13 +1977,28 @@ addpredefmacros(struct arena **tmparena) putmac(intern(macs[i].name), &macs[i].m); } - switch (targ_mcisa) { + switch (target.arch) { + default: assert(0); case ISx86_64: putdef1("__x86_64__"); putdef1("__x86_64"); break; } + if (target.os != OSunknown) putdef1("__STDC_HOSTED__"); + switch (target.os) { + default: assert(0); + case OSunknown: break; + case OSlinux: + putdef1("__linux__"); + putdef1("__linux"); + putdef1("linux"); + putdef1("unix"); + putdef1("__unix"); + putdef1("__unix__"); + break; + } + if (ppcmdline.n) { struct memfile *f; struct lexer lx[1] = {0}; @@ -160,9 +160,13 @@ extern struct inclpaths { /* Target */ /**********/ -enum mcisa { ISx86_64 }; +struct targtriple { + enum mcarch { ISxxx, ISx86_64 } arch; + enum mcos { OSunknown, OSlinux } os; + enum mcabi { ABInone, ABIgnu, ABImusl } abi; +}; extern const struct mctarg *mctarg; -extern enum mcisa targ_mcisa; +extern struct targtriple target; void targ_init(const char *); /*********/ diff --git a/hostconfig.h b/hostconfig.h new file mode 100644 index 0000000..b333ad2 --- /dev/null +++ b/hostconfig.h @@ -0,0 +1,27 @@ +#ifndef HOST_CONFIG_H +#define HOST_CONFIG_H + +#if defined __x86_64 || defined __x86_64__ +#define HOST_ARCH ISx86_64 +#else +#define HOST_ARCH ISxxx +#endif + +#if defined __linux__ +#define HOST_OS OSlinux +#else +#define HOST_OS OSunknown +#endif + +#if defined __linux__ +#define HOST_ABI ABIgnu +#else +#define HOST_ABI ABInone +#endif + +#ifndef HOST_INCLUDE_DIRS +#define HOST_INCLUDE_DIRS "/usr/include", "/usr/local/include" +#endif + +#endif + @@ -1094,7 +1094,7 @@ fatal(const struct span *span, const char *fmt, ...) va_start(ap, fmt); vdiag(span, DGERROR, fmt, ap); va_end(ap); - efmt("Aborting due to previous error.\n"); + if (span) efmt("Aborting due to previous error.\n"); exit(1); } @@ -1,4 +1,5 @@ #include "common.h" +#include "hostconfig.h" #include "obj/obj.h" #include <errno.h> #include <stdlib.h> @@ -165,6 +166,10 @@ optparse(char **args) if (!strcmp(flag, "pie") || !strcmp(flag, "PIE")) ccopt.pie = set; else if (!strcmp(flag, "pic") || !strcmp(flag, "PIC")) ccopt.pic = set; else goto Bad; + } else if (!strcmp(arg, "target") || !strcmp(arg, "-target")) { + const char *s = *++args; + if (!s) fatal(NULL, "missing target name"); + task.targ = s; } else if (*arg == 'l') { vpush(&task.linkargs, arg-1); } else if (!strcmp(arg, "v") || !strcmp(arg, "-verbose")) { @@ -249,7 +254,7 @@ tempfile(const char *path, const char *ext) while (*path) if (*path++ == '/') file = path; - bfmt(&fbuf, "%s/cc%x@%u@", tmpdir, id, id2++); + bfmt(&fbuf, "%s/antcc-%x@%u@", tmpdir, id, id2++); while (*file++) { char c = file[-1]; if (in_range(c, 'a', 'z') || in_range(c, 'A', 'Z') || in_range(c, '0', '9') @@ -322,18 +327,78 @@ compileobjs(void) } } +#include <fcntl.h> + +static bool +hasprog(const char *prog) +{ + pid_t p; + if ((p = fork()) < 0) { + return 0; + } else if (p == 0) { + int nulfd = open("/dev/null", O_WRONLY); + if (nulfd < 0) return 0; + for (int fd = 0; fd <= 2; ++fd) { + dup2(fd, nulfd); + close(fd); + } + const char *cmd[] = {"/bin/env", prog, NULL}; + if (execv(*cmd, (char **)cmd)) { + close(nulfd); + error(NULL, "execv: %s", strerror(errno)); + exit(125); + } + } + int wstat; + waitpid(p, &wstat, 0); + if (!WIFEXITED(wstat)) return 0; + return WEXITSTATUS(wstat) < 125; +} + +struct cmdargs { vec_of(const char *); }; + +static void +findlinkcmd(struct cmdargs *cmd) +{ + if (task.targ && (target.os != HOST_OS || target.arch != HOST_ARCH || target.abi != HOST_ABI)) { + static const char *ccs[] = {"cc", "gcc", "clang"}; + char cross[1024]; + for (int i = 0; i < countof(ccs); ++i) { + struct wbuf wbuf = MEMBUF(cross, sizeof cross); + int n = bfmt(&wbuf, "%s-%s", task.targ, ccs[i]); + assert(n < sizeof cross-1); + cross[n] = 0; + if (hasprog(cross)) { + vpush(cmd, alloccopy(&globarena, cross, n, 1)); + return; + } + } + if (hasprog("zig")) { + vpush(cmd, "zig"); + vpush(cmd, "cc"); + vpush(cmd, "-target"); + vpush(cmd, task.targ); + } else { + fatal(NULL, "cannot link to cross-compilation target: no appropiate toolchain installed"); + } + } else { + vpush(cmd, "cc"); + } +} + static int dolink(void) { - static const char *cmdbuf[10]; + const char *cmdbuf[100]; pid_t p; int wstat; - vec_of(const char *) cmd = VINIT(cmdbuf, countof(cmdbuf)); - - /* TODO don't depend on external c compiler, find lib and runtime paths and - * invoke linker directly.. */ + struct cmdargs cmd = VINIT(cmdbuf, countof(cmdbuf)); - vpush(&cmd, "/bin/gcc"); + vpush(&cmd, "/bin/env"); + findlinkcmd(&cmd); + if (!strcmp(cmd.p[1], "zig")) { + note(NULL, "using 'zig cc' as a cross-compiler"); + } if (task.outft == OFTdll) { vpush(&cmd, "-shared"); } else if (task.outft == OFTexe) { @@ -361,25 +426,30 @@ dolink(void) } vpush(&cmd, NULL); if ((p = fork()) < 0) { - error(NULL, "fork(): %s\n", strerror(errno)); + error(NULL, "fork: %s\n", strerror(errno)); exit(1); } else if (p == 0) { - if (!execv(cmd.p[0], (char **)cmd.p)) { - error(NULL, "execv(): %s\n", strerror(errno)); + if (execv(cmd.p[0], (char **)cmd.p)) { + error(NULL, "execv: %s\n", strerror(errno)); exit(1); } } vfree(&cmd); waitpid(p, &wstat, 0); if (!WIFEXITED(wstat)) return 127; - return WEXITSTATUS(wstat); + if (WEXITSTATUS(wstat) != 0) { + error(NULL, "link command failed"); + return 1; + } + return 0; } -#include <fcntl.h> /* open */ - static int dorun(void) { + if (target.arch != HOST_ARCH || target.os != HOST_OS) { + warn(NULL, "'-run' with cross-compiled binary"); + } if (task.verbose) { efmt("> exec %s", task.out); for (char **s = task.runargs; *s; ++s) @@ -388,18 +458,18 @@ dorun(void) } int fd = open(task.out, O_RDONLY); if (fd < 0) { - error(NULL, "open(): %s\n", strerror(errno)); + error(NULL, "open: %s\n", strerror(errno)); return 1; } if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { - error(NULL, "fcntl(): %s\n", strerror(errno)); + error(NULL, "fcntl: %s\n", strerror(errno)); return 1; } cleantemps(); extern char **environ; int fexecve(int fd, char *const argv[], char *const envp[]); fexecve(fd, task.runargs - 1, environ); - error(NULL, "fexecv(): %s\n", strerror(errno)); + error(NULL, "fexecv: %s\n", strerror(errno)); return 1; } @@ -485,8 +555,7 @@ static void sysinclpaths(void) { static const char *paths[] = { - "/usr/local/include", - "/usr/include" + HOST_INCLUDE_DIRS }; for (int i = 0; i < countof(paths); ++i) addinclpath(paths[i]); @@ -541,8 +610,9 @@ main(int argc, char **argv) optparse(argv); /* global init */ - task.targ = task.targ ? task.targ : "x86_64-sysv"; targ_init(task.targ); + if (!target.arch) + fatal(NULL, "unsupported target: %s", task.targ ? task.targ : "(host)"); return driver(); } @@ -46,7 +46,8 @@ elfinit(void) hdr.i_osabi = ELFOSABI_SYSV; hdr.i_abiversion = 0; hdr.h32.type = ET_REL; - switch (targ_mcisa) { + switch (target.arch) { + default: assert(!"arch?"); case ISx86_64: hdr.h32.machine = EM_X86_64; break; } hdr.h32.version = ELFVERSION; @@ -154,7 +155,7 @@ elfreloc(internstr sym, enum relockind kind, enum section section, uint off, vlo case Sdata: ++ndatarel; break; } assert(kind < NRELOCKIND); - vpush(&relocs, ((struct reloc) { section, relktab[targ_mcisa][kind], off, addend, .symname = sym })); + vpush(&relocs, ((struct reloc) { section, relktab[target.arch][kind], off, addend, .symname = sym })); } static void @@ -372,7 +373,7 @@ elffini(struct wbuf *out) shnam_strtab = 36, shnam_symtab = 44, shnam_reltext = 52, shnam_relrodata = 63, shnam_reldata = 76 }; int align = targ_64bit ? 8 : 4; - bool userela = userelatab[targ_mcisa]; + bool userela = userelatab[target.arch]; char shstrs[] = "\0.text\0.rodata\0.data\0.bss\0.shstrtab\0.strtab\0.symtab\0" ".rela.text\0.rela.rodata\0.rela.data"; if (!userela) { @@ -3,32 +3,78 @@ extern const struct mctarg t_x86_64_sysv; static const struct targ { - const char *name; + struct { enum mcarch arch; uint oss, abis; }; struct { uchar longsize, vlongsize, ptrsize, valistsize; }; struct { uchar longalign, vlongalign, doublealign, ptralign; }; bool charsigned; uchar sizetype, ptrdifftype, wchartype; const struct mctarg *mctarg; - enum mcisa isa; } targs[] = { - { "x86_64-sysv", {8, 8, 8, 24}, {8, 8, 8, 8}, 1, TYULONG, TYLONG, TYINT, &t_x86_64_sysv, ISx86_64 }, - { "i686-sysv", {4, 8, 4, 8}, {4, 4, 4, 4}, 1, TYUINT, TYINT, TYINT } + { {ISx86_64, -1, 1<<ABIgnu | 1<<ABImusl}, {8,8,8,24}, {8,8,8,8}, 1, TYULONG, TYLONG, TYINT, &t_x86_64_sysv }, }; +struct targtriple target; uchar targ_primsizes[TYPTR+1]; uchar targ_primalign[TYPTR+1]; uint targ_valistsize; enum typetag targ_sizetype, targ_ptrdifftype, targ_wchartype; bool targ_charsigned, targ_bigendian, targ_64bit; -enum mcisa targ_mcisa; +enum mcarch targ_arch; const struct mctarg *mctarg; +static bool +matchstr(const char **s, const char *pat) +{ + const char *p; + for (p = *s; *pat; ++p, ++pat) { + if (*pat == '$') { if (*p) return 0; else break; } + else if (*p != *pat) return 0; + } + *s = p; + return 1; +} + +static bool +parsetriple(struct targtriple *trg, const char *str) +{ + if (matchstr(&str, "x86_64-")) { + trg->arch = ISx86_64; + } else return 0; + + if (matchstr(&str, "unknown-") || matchstr(&str, "pc-")) {} + + if (matchstr(&str, "linux-")) { + trg->os = OSlinux; + } else if (matchstr(&str, "linux$")) { + trg->os = OSlinux; + trg->abi = ABIgnu; + } else return 0; + + if (matchstr(&str, "gnu")) { + trg->abi = ABIgnu; + } else if (matchstr(&str, "musl")) { + trg->abi = ABImusl; + } else return 0; + + return 1; +} + +#include "hostconfig.h" + void targ_init(const char *starg) { const struct targ *t = &targs[0]; uchar *sizes = targ_primsizes, *align = targ_primalign; + if (!starg) { + target.arch = HOST_ARCH; + target.os = HOST_OS; + target.abi = HOST_ABI; + } else if (!parsetriple(&target, starg)) { + fatal(NULL, "unrecognized target: %s", starg); + } + sizes[TYBOOL] = sizes[TYCHAR] = sizes[TYSCHAR] = sizes[TYUCHAR] = 1; sizes[TYSHORT] = sizes[TYUSHORT] = 2; sizes[TYUINT] = sizes[TYINT] = 4; @@ -52,4 +98,5 @@ targ_init(const char *starg) targ_bigendian = 0; targ_64bit = t->ptrsize == 8; mctarg = t->mctarg; + targ_arch = ISx86_64; } |