ref: fcc4d827f855bae3c6e3f1fb7eaaec326bc4765c
parent: 8370fd16f8e62614b67941b32e2cd0e00fcc6e02
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Tue Mar 13 15:46:42 EDT 2018
[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.
--- a/ld/Makefile
+++ b/ld/Makefile
@@ -5,7 +5,7 @@
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 @@
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
--- /dev/null
+++ b/ld/coff32.c
@@ -1,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,
+};
--- /dev/null
+++ b/ld/formats.c
@@ -1,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,
+};
--- /dev/null
+++ b/ld/ld.h
@@ -1,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);
+};
--- 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;
}