scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | README | LICENSE

commit b8a1d2ca3e81343682767155f070b21e0a78fc1b
parent 2f015a12ce5987228380452a9361a4a2c5bc5901
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Tue, 13 Mar 2018 19:46:42 +0100

[ld] Add basic support for objects and libraries

This code is still a skeleton, but this skeleton is taken from
nm because they have to run over the same kind of archives.

Diffstat:
Mld/Makefile | 8+++++++-
Ald/coff32.c | 26++++++++++++++++++++++++++
Ald/formats.c | 13+++++++++++++
Ald/ld.h | 6++++++
Mld/main.c | 218+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 270 insertions(+), 1 deletion(-)

diff --git a/ld/Makefile b/ld/Makefile @@ -5,7 +5,7 @@ LIBDIR = $(PROJECTDIR)/lib/scc include $(PROJECTDIR)/rules.mk include $(LIBDIR)/libdep.mk -OBJ = main.o +OBJ = main.o formats.o coff32.o all: ld mkdir -p $(PROJECTDIR) @@ -26,3 +26,9 @@ clean: distclean: clean #deps +coff32.c: ld.h +formats.c: ld.h +main.c: ../inc/arg.h +main.c: ../inc/ar.h +main.c: ../inc/scc.h +main.c: ld.h diff --git a/ld/coff32.c b/ld/coff32.c @@ -0,0 +1,26 @@ +static char sccsid[] = "@(#) ./ld/coff32.c"; + +#include <stdio.h> + +#include "ld.h" + +static int +probe(char *fname, char *member, FILE *fp) +{ +} + +static int +pass1(char *fname, char *member, FILE *fp) +{ +} + +static int +pass2(char *fname, char *member, FILE *fp) +{ +} + +struct objfile coff32 = { + .probe = probe, + .pass1 = pass1, + .pass2 = pass2, +}; diff --git a/ld/formats.c b/ld/formats.c @@ -0,0 +1,13 @@ +static char sccsid[] = "@(#) ./ld/probe.c"; + +#include <stdio.h> + +#include "ld.h" + +/* TODO: Autogenerate this file */ +struct objfile coff32; + +struct objfile *formats[] = { + &coff32, + NULL, +}; diff --git a/ld/ld.h b/ld/ld.h @@ -0,0 +1,6 @@ + +struct objfile { + int (*probe)(char *fname, char *member, FILE *fp); + int (*pass1)(char *fname, char *member, FILE *fp); + int (*pass2)(char *fname, char *member, FILE *fp); +}; diff --git a/ld/main.c b/ld/main.c @@ -1,12 +1,230 @@ static char sccsid[] = "@(#) ./ld/main.c"; +#include <ctype.h> +#include <errno.h> +#include <limits.h> #include <stdio.h> +#include <stdlib.h> +#include <string.h> #include "../inc/arg.h" #include "../inc/scc.h" +#include "../inc/ar.h" +#include "ld.h" + +char *argv0; +int pass; + +static int +object(char *fname, char *member, FILE *fp) +{ + extern struct objfile *formats[]; + struct objfile **p, *obj; + void *data; + int (*fun)(char *, char *, FILE *); + + for (p = formats; *p; ++p) { + obj = *p; + if ((*obj->probe)(fname, member, fp)) + break; + } + if (*p == NULL) + return 0; + + fun = (pass == 1) ? obj->pass1 : obj->pass2; + return (*fun)(fname, member, fp); +} + +static char * +getfname(struct ar_hdr *hdr, char *dst) +{ + char *p; + int i; + + memcpy(dst, hdr->ar_name, SARNAM); + dst[SARNAM] = '\0'; + + for (i = SARNAM-1; i >= 0; i--) { + if (dst[i] != ' ' && dst[i] != '/') + break; + dst[i] = '\0'; + } + return dst; +} + +static void +ar(char *fname, FILE *fp) +{ + struct ar_hdr hdr; + long pos, siz; + char member[SARNAM+1]; + + if (fseek(fp, SARMAG, SEEK_SET) == EOF) + goto file_error; + + while (fread(&hdr, sizeof(hdr), 1, fp) == 1) { + pos = ftell(fp); + if (strncmp(hdr.ar_fmag, ARFMAG, sizeof(hdr.ar_fmag))) + goto corrupted; + + siz = 0; + sscanf(hdr.ar_size, "%10ld", &siz); + if (siz == 0) + goto corrupted; + + if (siz & 1) + siz++; + if (pos == -1 || pos > LONG_MAX - siz) + die("ld: %s: overflow in size of archive", fname); + pos += siz; + + getfname(&hdr, member); + object(fname, member, fp); + if (fseek(fp, pos, SEEK_SET) == EOF) + goto file_error; + } + + if (ferror(fp)) + goto file_error; + return; + +corrupted: + die("ld: %s: corrupted archive", fname); +file_error: + die("ld: %s: %s", fname, strerror(errno)); +} + +static int +archive(char *fname, FILE *fp) +{ + char magic[SARMAG]; + fpos_t pos; + + fgetpos(fp, &pos); + fread(magic, SARMAG, 1, fp); + fsetpos(fp, &pos); + + if (ferror(fp)) + die("ld: %s: %s", fname, strerror(errno)); + if (strncmp(magic, ARMAG, SARMAG) != 0) + return 0; + + ar(fname, fp); + return 1; +} + +static void +process(char *fname) +{ + FILE *fp; + + if ((fp = fopen(fname, "rb")) == NULL) + die("ld: %s: %s", fname, strerror(errno)); + + if (!object(fname, fname, fp) && !archive(fname, fp)) + die("ld: %s: File format not recognized", fname); + + if (ferror(fp)) + die("ld: %s: %s", fname, strerror(errno)); + + fclose(fp); +} + +static void +pass1(struct items *list) +{ + unsigned i; + + pass = 1; + for (i = 0; i < list->n; ++i) + process(list->s[i]); +} + +static void +pass2(struct items *list) +{ + unsigned i; + + pass = 2; + for (i = 0; i < list->n; ++i) + process(list->s[i]); +} + +static void +readflist(struct items *list, char *fname) +{ + FILE *fp; + char line[FILENAME_MAX]; + unsigned char *s, *t; + + if ((fp = fopen(fname, "rb")) == NULL) + die("ld: %s: %s", fname, strerror(errno)); + + while (fgets(line, sizeof(line), fp)) { + size_t n = strlen(line); + if (n == 0) + continue; + if (line[n-1] != '\n') + die("ld: %s: line too long", fname); + for (s = line; isspace(*s); ++s) + *s = '\0'; + for (t = &line[n-1]; isspace(*t); --t) + *t = '\0'; + newitem(list, xstrdup(s)); + } + + if (ferror(fp)) + die("ld: %s: %s", fname, strerror(errno)); + + fclose(fp); +} + +static void +usage(void) +{ + fputs("usage: ld [options] [@file] file ...\n", stderr); + exit(1); +} int main(int argc, char *argv[]) { + unsigned i; + struct items flist = {.n = 0}; + + ARGBEGIN { + case 's': + case 'u': + case 'l': + case 'x': + case 'X': + case 'r': + case 'd': + case 'n': + case 'i': + case 'o': + case 'e': + case 'O': + case 'D': + break; + default: + usage(); + } ARGEND + + + if (argc == 0) + usage(); + + if (*argv[0] == '@') { + readflist(&flist, *argv + 1); + ++argv; + } + + for (; *argv; ++argv) + newitem(&flist, *argv); + + pass1(&flist); + pass2(&flist); + return 0; }