diff --git a/as/0LD/main.c b/as/0LD/main.c deleted file mode 100644 index ffc4cb5..0000000 --- a/as/0LD/main.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * main.c - */ -#include -#include -#include "pass1.h" - -int main(int argc, char **argv) -{ - int ch; - const char *outfile = "a.out"; - const char *infile = NULL; - - for (;;) { - ch = getopt(argc, argv, "o:"); - switch (ch) { - case 'o': - outfile = optarg; - continue; - case -1: - break; - default: - fprintf(stderr, "as: invalid option '%c'\n", ch); - return 1; - } - } - if (optind + 1 == argc) - infile = argv[optind]; - - if (pass1(infile) < 0) - return 1; - - if (pass2() < 0) - return 1; - - if (pass3(outfile) < 0) - return 1; - - return 0; -} diff --git a/as/0LD/parse.h b/as/0LD/parse.h deleted file mode 100644 index 919181a..0000000 --- a/as/0LD/parse.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * parse.h - */ -#ifndef PARSE_H -#define PARSE_H - -#include "stmt.h" - -int parse_stmt(struct stmt *stmt); - -#endif /* PARSE_H */ diff --git a/as/0LD/scan.h b/as/0LD/scan.h deleted file mode 100644 index 46472e2..0000000 --- a/as/0LD/scan.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * scan.h - */ -#ifndef SCAN_H -#define SCAN_H - -#include "token.h" - -const char *scan_filename; -int scan_freopen(const char *filename); - -unsigned int scan_linenr; -enum token scan(union token_attribute *token_attr); - -#endif /* SCAN_H */ diff --git a/as/0LD/token.def b/as/0LD/token.def deleted file mode 100644 index c073d0e..0000000 --- a/as/0LD/token.def +++ /dev/null @@ -1,77 +0,0 @@ -/* - * token.def - * - * TOKEN(T_, , ) - */ - -/* directives */ -TOKEN(T_DOT_ALIGN, ".align", FMT_NONE) -TOKEN(T_DOT_ASCII, ".ascii", FMT_NONE) -TOKEN(T_DOT_ASCIZ, ".asciz", FMT_NONE) -TOKEN(T_DOT_BALIGN, ".balign", FMT_NONE) -TOKEN(T_DOT_BSS, ".bss", FMT_NONE) -TOKEN(T_DOT_BYTE, ".byte", FMT_NONE) -TOKEN(T_DOT_COMM, ".comm", FMT_NONE) -TOKEN(T_DOT_DATA, ".data", FMT_NONE) -TOKEN(T_DOT_FILE, ".file", FMT_NONE) -TOKEN(T_DOT_GLOBL, ".globl", FMT_NONE) -TOKEN(T_DOT_HIDDEN, ".hidden", FMT_NONE) -TOKEN(T_DOT_IDENT, ".ident", FMT_NONE) -TOKEN(T_DOT_INTERNAL, ".internal", FMT_NONE) -TOKEN(T_DOT_LOCAL, ".local", FMT_NONE) -TOKEN(T_DOT_LONG, ".long", FMT_NONE) -TOKEN(T_DOT_ORG, ".org", FMT_NONE) -TOKEN(T_DOT_P2ALIGN, ".p2align", FMT_NONE) -TOKEN(T_DOT_POPSECTION, ".popsection", FMT_NONE) -TOKEN(T_DOT_PREVIOUS, ".previous", FMT_NONE) -TOKEN(T_DOT_PROTECTED, ".protected", FMT_NONE) -TOKEN(T_DOT_PUSHSECTION, ".pushsection", FMT_NONE) -TOKEN(T_DOT_RODATA, ".rodata", FMT_NONE) -TOKEN(T_DOT_SECTION, ".section", FMT_NONE) -TOKEN(T_DOT_SET, ".set", FMT_NONE) -TOKEN(T_DOT_SHORT, ".short", FMT_NONE) -TOKEN(T_DOT_SIZE, ".size", FMT_NONE) -TOKEN(T_DOT_SUBSECTION, ".subsection", FMT_NONE) -TOKEN(T_DOT_SYMVER, ".symver", FMT_NONE) -TOKEN(T_DOT_TEXT, ".text", FMT_NONE) -TOKEN(T_DOT_TYPE, ".type", FMT_NONE) -TOKEN(T_DOT_WEAK, ".weak", FMT_NONE) -TOKEN(T_DOT_WEAKREF, ".weakref", FMT_NONE) -/* other symbols */ -TOKEN(T_REGISTER, "", FMT_UINT) -TOKEN(T_SYMBOL, "", FMT_SYMBOL) -TOKEN(T_LOCAL_LABEL, "", FMT_UINT) /* 1f, 2b */ -TOKEN(T_AT, "@", FMT_NONE) -TOKEN(T_COLON, ":", FMT_NONE) -/* literals */ -TOKEN(T_UINTEGER, "", FMT_UINT) -TOKEN(T_STRING, "", FMT_STRING) -/* operators, separators */ -TOKEN(T_COMMA, ",", FMT_NONE) -TOKEN(T_LPAREN, "(", FMT_NONE) -TOKEN(T_RPAREN, ")", FMT_NONE) -TOKEN(T_TILDE, "~", FMT_NONE) -TOKEN(T_MUL, "*", FMT_NONE) -TOKEN(T_DIV, "/", FMT_NONE) -TOKEN(T_REM, "%", FMT_NONE) -TOKEN(T_LSHIFT, "<<", FMT_NONE) -TOKEN(T_RSHIFT, ">>", FMT_NONE) -TOKEN(T_OR, "|", FMT_NONE) -TOKEN(T_AND, "&", FMT_NONE) -TOKEN(T_CARET, "^", FMT_NONE) -TOKEN(T_BANG, "!", FMT_NONE) -TOKEN(T_PLUS, "+", FMT_NONE) -TOKEN(T_MINUS, "-", FMT_NONE) -TOKEN(T_EQ, "=", FMT_NONE) -TOKEN(T_EQEQ, "==", FMT_NONE) -TOKEN(T_NEQ, "!=", FMT_NONE) -TOKEN(T_LT, "<", FMT_NONE) -TOKEN(T_GT, ">", FMT_NONE) -TOKEN(T_GE, ">=", FMT_NONE) -TOKEN(T_LE, "<=", FMT_NONE) -TOKEN(T_ANDAND, "&&", FMT_NONE) -TOKEN(T_OROR, "||", FMT_NONE) -/* misc */ -TOKEN(T_NEWLINE, "", FMT_NONE) -TOKEN(T_EOF, "", FMT_NONE) -TOKEN(T_ERROR, "", FMT_NONE) diff --git a/as/0LD/token.h b/as/0LD/token.h deleted file mode 100644 index d1be4ff..0000000 --- a/as/0LD/token.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * token.h - */ -#ifndef TOKEN_H -#define TOKEN_H - -#include "pdp10-stdint.h" - -enum token { -#define TOKEN(T,P,F) T, -#include "token.def" -#undef TOKEN -}; - -union token_attribute { - const char *text; /* symbol, string */ - pdp10_uint36_t uint; /* uinteger */ -}; - -void token_print(FILE *fp, enum token token, const union token_attribute *token_attr); - -#endif /* TOKEN_H */ diff --git a/as/Makefile b/as/Makefile new file mode 100644 index 0000000..1afe2cc --- /dev/null +++ b/as/Makefile @@ -0,0 +1,19 @@ +CC=gcc +CFLAGS=-O2 -g -Wall +CPPFLAGS=-I../include + +ASOBJS=assemble.o input.o main.o output.o parse.o scan.o token.o +LIBOBJS=../lib/pdp10-elf36.o ../lib/pdp10-extint.o ../lib/pdp10-opcodes.o ../lib/pdp10-stdio.o + +as: $(ASOBJS) $(LIBOBJS) + $(LINK.c) -o $@ $^ + +input.o: input.h parse.h scan.h token.def token.h +main.o: assemble.h input.h output.h +output.o: assemble.h output.h +parse.o: input.h scan.h token.def token.h +scan.o: scan.h token.def token.h +token.o: token.def token.h + +clean: + rm -f $(ASOBJS) as a.out core.* diff --git a/as/assemble.c b/as/assemble.c new file mode 100644 index 0000000..1c07e42 --- /dev/null +++ b/as/assemble.c @@ -0,0 +1,106 @@ +/* + * assemble.c + */ +#include +#include +#include +#include +#include "assemble.h" +#include "input.h" + +static struct aunit_symbol *symbol(const char *progname, struct aunit *aunit, const char *name) +{ + struct aunit_symbol *sym; + + for (sym = aunit->symbols; sym; sym = sym->next) + if (strcmp(name, sym->name) == 0) + return sym; + + sym = malloc(sizeof *sym); + if (!sym) { + fprintf(stderr, "%s: failed to allocate %zu bytes for aunit_symbol: %s\n", progname, sizeof *sym, strerror(errno)); + return NULL; + } + + sym->name = name; + sym->text_offset = 0; + sym->is_global = 0; + sym->is_defined = 0; + + sym->next = aunit->symbols; + aunit->symbols = sym; + + return sym; +} + +int assemble(const char *progname, struct iunit *iunit, struct aunit *aunit) +{ + struct stmt *stmt; + struct aunit_symbol *sym; + pdp10_uint36_t i, n; + + aunit->text_words = NULL; + aunit->text_nr_words = 0; + aunit->symbols = NULL; + + n = 0; + for (stmt = iunit->text.head; stmt; stmt = stmt->next) { + switch (stmt->tag) { + case S_DOT_GLOBL: + sym = symbol(progname, aunit, stmt->u.symbol.name); + if (!sym) + return -1; + sym->is_global = 1; + break; + case S_LABEL: + (void)symbol(progname, aunit, stmt->u.symbol.name); + break; + case S_INSN: + ++n; + break; + default: + break; + } + } + + aunit->text_nr_words = n; + aunit->text_words = malloc(n * sizeof(pdp10_uint36_t)); + if (!aunit->text_words) { + fprintf(stderr, "%s: failed to allocate %zu bytes for text image: %s\n", progname, n * sizeof(pdp10_uint36_t), strerror(errno)); + return -1; + } + + i = 0; + for (stmt = iunit->text.head; stmt; stmt = stmt->next) { + switch (stmt->tag) { + case S_LABEL: + sym = symbol(progname, aunit, stmt->u.symbol.name); + if (!sym) + return -1; + sym->is_defined = 1; + sym->text_offset = i * 4; + break; + case S_INSN: + if (i >= n) { + fprintf(stderr, "%s: internal error: text image overflow\n", progname); + return -1; + } + aunit->text_words[i] = + ((pdp10_uint36_t)(stmt->u.insn.opcode & 0x1FF) << (36 - 9) + | ((stmt->u.insn.accumulator & 0xF) << (36 - 13)) + | ((stmt->u.insn.at & 1) << (36 - 14)) + | ((stmt->u.insn.indexreg & 0xF) << (36 - 18)) + | (stmt->u.insn.address & PDP10_UINT18_MAX)); + ++i; + break; + default: + break; + } + } + if (i != n) { + fprintf(stderr, "%s: internal error: text image size mismatch\n", progname); + return -1; + } + + return 0; +} diff --git a/as/assemble.h b/as/assemble.h new file mode 100644 index 0000000..0641caf --- /dev/null +++ b/as/assemble.h @@ -0,0 +1,26 @@ +/* + * assemble.h + */ +#ifndef ASSEMBLE_H +#define ASSEMBLE_H + +#include "pdp10-stdint.h" +#include "input.h" + +struct aunit_symbol { + struct aunit_symbol *next; + const char *name; + pdp10_uint36_t text_offset; + int is_global; + int is_defined; +}; + +struct aunit { + pdp10_uint36_t *text_words; + pdp10_uint36_t text_nr_words; + struct aunit_symbol *symbols; +}; + +int assemble(const char *progname, struct iunit *iunit, struct aunit *aunit); + +#endif /* ASSEMBLE_H */ diff --git a/as/input.c b/as/input.c new file mode 100644 index 0000000..494b1a8 --- /dev/null +++ b/as/input.c @@ -0,0 +1,85 @@ +/* + * input.c + */ +#include +#include +#include +#include +#include "input.h" +#include "parse.h" +#include "scan.h" + +static int interpret(struct scan_state *scan_state, struct iunit *iunit, struct stmt *stmt) +{ + struct stmt *stmt2; + + switch (stmt->tag) { + case S_DOT_GLOBL: + break; + case S_DOT_TEXT: + return 0; /* XXX: nothing to do yet */ + case S_LABEL: + break; + case S_INSN: + break; + default: + fprintf(stderr, "%s: %s line %u: parser returned unexpected stmt->tag %u\n", + scan_state->progname, scan_state->filename, scan_state->linenr, stmt->tag); + return -1; + } + + stmt2 = malloc(sizeof *stmt2); + if (!stmt2) { + fprintf(stderr, "%s: %s line %u: malloc(%zu) failed: %s\n", + scan_state->progname, scan_state->filename, scan_state->linenr, sizeof *stmt2, strerror(errno)); + return -1; + } + + *stmt2 = *stmt; + stmt2->next = NULL; + + *iunit->text.tailptr = stmt2; + iunit->text.tailptr = &stmt2->next; + + return 0; +} + +int input(const char *progname, char **files, int nrfiles, struct iunit *iunit) +{ + char fake_file[3]; + char *fake_files[1]; + struct scan_state scan_state; + int i; + struct stmt stmt; + int status; + + if (nrfiles <= 0) { + fake_file[0] = '-'; + fake_file[1] = '-'; + fake_file[2] = '\0'; + fake_files[0] = fake_file; + files = fake_files; + nrfiles = 1; + } + + iunit->text.head = NULL; + iunit->text.tailptr = &iunit->text.head; + + scan_init(&scan_state, progname); + + for (i = 0; i < nrfiles; ++i) { + if (scan_open(&scan_state, files[i]) < 0) + return -1; + for (;;) { + status = parse_stmt(&scan_state, &stmt); + if (status < 0) + return -1; + if (status == 0) + break; + if (interpret(&scan_state, iunit, &stmt) < 0) + return -1; + } + } + + return 0; +} diff --git a/as/input.h b/as/input.h new file mode 100644 index 0000000..687dd90 --- /dev/null +++ b/as/input.h @@ -0,0 +1,53 @@ +/* + * input.h + */ +#ifndef INPUT_H +#define INPUT_H + +/* + * A directives, label, or instruction is parsed to a statement, which is + * either interpreted immediately or appended to the representation of the + * current section. + */ + +enum stmt_tag { + /* directives */ + S_DOT_GLOBL, + S_DOT_TEXT, + /* non-directives */ + S_LABEL, + S_INSN, +}; + +struct stmt { + struct stmt *next; + enum stmt_tag tag; + union { + struct { /* S_DOT_GLOBL, S_LABEL */ + const char *name; + } symbol; + struct { /* S_INSN */ + unsigned int opcode; + unsigned int accumulator; + int at; + unsigned int address; /* XXX: relocatable expr */ + unsigned int indexreg; + } insn; + } u; +}; + +/* + * The input unit object is the top-level container for the representation + * of the sections, and all other information collected from the input. + */ + +struct iunit { + struct { + struct stmt *head; + struct stmt **tailptr; + } text; +}; + +int input(const char *progname, char **files, int nrfiles, struct iunit *iunit); + +#endif /* INPUT_H */ diff --git a/as/main.c b/as/main.c new file mode 100644 index 0000000..143f8a4 --- /dev/null +++ b/as/main.c @@ -0,0 +1,52 @@ +/* + * main.c + * + * as clone for PDP10 with Elf36 object files. + */ +#include +#include +#include "assemble.h" +#include "input.h" +#include "output.h" + +#define VERSION "pdp10-tools as version 0.1, built " __DATE__ " " __TIME__ "\n" + +int main(int argc, char **argv) +{ + const char *outfile = "a.out"; + struct iunit iunit; + struct aunit aunit; + + for (;;) { + int ch; + + ch = getopt(argc, argv, "vo:"); + switch (ch) { + case 'v': + printf(VERSION); + continue; + case 'o': + outfile = optarg; + continue; + case -1: + break; + default: + fprintf(stderr, "Usage: %s [-v] [-o outfile] [files..]\n", argv[0]); + return 1; + } + break; + } + + if (input(argv[0], &argv[optind], argc - optind, &iunit) < 0) + return 1; + + if (assemble(argv[0], &iunit, &aunit) < 0) + return 1; + + /* XXX: iunit_fini(&iunit) */ + + if (output(argv[0], &aunit, outfile) < 0) + return 1; + + return 0; +} diff --git a/as/output.c b/as/output.c new file mode 100644 index 0000000..bf51adb --- /dev/null +++ b/as/output.c @@ -0,0 +1,325 @@ +/* + * output.c + */ +#include +#include +#include +#include +#include "pdp10-elf36.h" +#include "pdp10-stdint.h" +#include "pdp10-stdio.h" +#include "assemble.h" +#include "output.h" + +struct strtab_entry { + struct strtab_entry *next; + const char *string; + unsigned int nrbytes; /* strlen(string) + 1 */ +}; + +struct strtab { + struct strtab_entry *head; + unsigned int nrbytes; +}; + +static void strtab_init(struct strtab *strtab) +{ + strtab->head = NULL; + strtab->nrbytes = 0; +} + +static pdp10_uint36_t strtab_enter(const char *progname, struct strtab *strtab, const char *name) +{ + struct strtab_entry *prev, *here; + pdp10_uint36_t index; + + index = 1; + prev = NULL; + here = strtab->head; + while (here != NULL) { + if (strcmp(name, here->string) == 0) + return index; + index += here->nrbytes; + prev = here; + here = here->next; + } + + here = malloc(sizeof *here); + if (!here) { + fprintf(stderr, "%s: failed to allocate %zu bytes for a strtab_entry: %s\n", + progname, sizeof *here, strerror(errno)); + return 0; + } + here->next = NULL; + here->string = name; + here->nrbytes = strlen(name) + 1; + + if (prev) { + prev->next = here; + } else { + strtab->head = here; + index = 1; + strtab->nrbytes = 1; + } + + strtab->nrbytes += here->nrbytes; + + return index; +} + +static int strtab_write(PDP10_FILE *pdp10fp, const struct strtab *strtab) +{ + struct strtab_entry *here; + unsigned int i; + + if (pdp10_elf36_write_uint9(pdp10fp, '\0') < 0) + return -1; + + for (here = strtab->head; here; here = here->next) + for (i = 0; i < here->nrbytes; ++i) + if (pdp10_elf36_write_uint9(pdp10fp, here->string[i]) < 0) + return -1; + + i = (4 - (strtab->nrbytes & 3)) & 3; + while (i != 0) { + if (pdp10_elf36_write_uint9(pdp10fp, '\0') < 0) + return -1; + --i; + } + + return 0; +} + +int output(const char *progname, struct aunit *aunit, const char *outfile) +{ + pdp10_uint36_t shnum, text_shndx, symtab_shndx, strtab_shndx, shstrtab_shndx; + pdp10_uint36_t text_shstrndx, symtab_shstrndx, strtab_shstrndx, shstrtab_shstrndx; + Elf36_Sym *symtab; + pdp10_uint36_t symnum; + struct strtab strtab, shstrtab; + struct aunit_symbol *asym; + pdp10_uint36_t i; + Elf36_Shdr *shtab; + pdp10_uint36_t offset; + Elf36_Ehdr ehdr; + PDP10_FILE *pdp10fp; + + shnum = 0; + shstrtab_shndx = 0; + text_shndx = 0; + symtab_shndx = 0; + strtab_shndx = 0; + symtab = NULL; + symnum = 0; + strtab_init(&strtab); + strtab_init(&shstrtab); + shtab = NULL; + + shnum = 1; /* tentative */ + + if (aunit->text_nr_words != 0) { + text_shstrndx = strtab_enter(progname, &shstrtab, ".text"); + if (text_shstrndx == 0) + return -1; + text_shndx = shnum; + ++shnum; + } + + for (asym = aunit->symbols; asym; asym = asym->next) + ++symnum; + if (symnum != 0) { + symtab_shstrndx = strtab_enter(progname, &shstrtab, ".symtab"); + if (symtab_shstrndx == 0) + return -1; + strtab_shstrndx = strtab_enter(progname, &shstrtab, ".strtab"); + if (strtab_shstrndx == 0) + return -1; + symtab_shndx = shnum; + strtab_shndx = shnum + 1; + shnum += 2; + } + + if (shnum == 1) { + shstrtab_shndx = 0; + shnum = 0; + } else { + shstrtab_shstrndx = strtab_enter(progname, &shstrtab, ".shstrtab"); + if (shstrtab_shstrndx == 0) + return -1; + shstrtab_shndx = shnum; + ++shnum; + } + + if (symnum) { + ++symnum; /* for initial stub entry */ + symtab = malloc(symnum * sizeof(Elf36_Sym)); + if (!symtab) { + fprintf(stderr, "%s: failed to allocate %zu bytes for Elf36 symbol table: %s\n", + progname, symnum * sizeof(Elf36_Sym), strerror(errno)); + return -1; + } + + symtab[0].st_name = 0; + symtab[0].st_value = 0; + symtab[0].st_size = 0; + symtab[0].st_info = ELF36_ST_INFO(STB_LOCAL, STT_NOTYPE); + symtab[0].st_other = 0; + symtab[0].st_shndx = SHN_UNDEF; + + for (i = 1, asym = aunit->symbols; asym; ++i, asym = asym->next) { + symtab[i].st_name = strtab_enter(progname, &strtab, asym->name); + if (symtab[i].st_name == 0) + return -1; + symtab[i].st_value = asym->text_offset; + symtab[i].st_size = 0; + if (asym->is_global) + symtab[i].st_info = ELF36_ST_INFO(STB_GLOBAL, STT_NOTYPE); + else + symtab[i].st_info = ELF36_ST_INFO(STB_LOCAL, STT_NOTYPE); + symtab[i].st_other = STV_DEFAULT; + symtab[i].st_shndx = text_shndx; + } + } + + if (shnum) { + shtab = malloc(shnum * sizeof(Elf36_Shdr)); + if (!shtab) { + fprintf(stderr, "%s: failed to allocate %zu bytes for Elf36 section header table: %s\n", + progname, shnum * sizeof(Elf36_Shdr), strerror(errno)); + return -1; + } + + shtab[0].sh_name = 0; + shtab[0].sh_type = SHT_NULL; + shtab[0].sh_flags = 0; + shtab[0].sh_addr = 0; + shtab[0].sh_offset = 0; + shtab[0].sh_size = 0; + shtab[0].sh_link = 0; + shtab[0].sh_info = 0; + shtab[0].sh_addralign = 0; + shtab[0].sh_entsize = 0; + + offset = ELF36_EHDR_SIZEOF; + + if (text_shndx) { + shtab[text_shndx].sh_name = text_shstrndx; + shtab[text_shndx].sh_type = SHT_PROGBITS; + shtab[text_shndx].sh_flags = SHF_ALLOC | SHF_EXECINSTR; + shtab[text_shndx].sh_addr = 0; + shtab[text_shndx].sh_offset = offset; + shtab[text_shndx].sh_size = aunit->text_nr_words * 4; + shtab[text_shndx].sh_link = 0; + shtab[text_shndx].sh_info = 0; + shtab[text_shndx].sh_addralign = 4; + shtab[text_shndx].sh_entsize = 0; + offset += aunit->text_nr_words * 4; + } + + if (symtab_shndx) { + shtab[symtab_shndx].sh_name = symtab_shstrndx; + shtab[symtab_shndx].sh_type = SHT_SYMTAB; + shtab[symtab_shndx].sh_flags = 0; + shtab[symtab_shndx].sh_addr = 0; + shtab[symtab_shndx].sh_offset = offset; + shtab[symtab_shndx].sh_size = symnum * ELF36_SYM_SIZEOF; + shtab[symtab_shndx].sh_link = strtab_shndx; + shtab[symtab_shndx].sh_info = 0 + 1; /* XXX: LAST_LOCAL + 1 */ + shtab[symtab_shndx].sh_addralign = 4; + shtab[symtab_shndx].sh_entsize = ELF36_SYM_SIZEOF; + offset += symnum * ELF36_SYM_SIZEOF; + } + + if (strtab_shndx) { + shtab[strtab_shndx].sh_name = strtab_shstrndx; + shtab[strtab_shndx].sh_type = SHT_STRTAB; + shtab[strtab_shndx].sh_flags = 0; + shtab[strtab_shndx].sh_addr = 0; + shtab[strtab_shndx].sh_offset = offset; + shtab[strtab_shndx].sh_size = strtab.nrbytes; + shtab[strtab_shndx].sh_link = 0; + shtab[strtab_shndx].sh_info = 0; + shtab[strtab_shndx].sh_addralign = 1; + shtab[strtab_shndx].sh_entsize = 0; + offset += (strtab.nrbytes + 3) & ~3; + } + + if (shstrtab_shndx) { + shtab[shstrtab_shndx].sh_name = shstrtab_shstrndx; + shtab[shstrtab_shndx].sh_type = SHT_STRTAB; + shtab[shstrtab_shndx].sh_flags = 0; + shtab[shstrtab_shndx].sh_addr = 0; + shtab[shstrtab_shndx].sh_offset = offset; + shtab[shstrtab_shndx].sh_size = shstrtab.nrbytes; + shtab[shstrtab_shndx].sh_link = 0; + shtab[shstrtab_shndx].sh_info = 0; + shtab[shstrtab_shndx].sh_addralign = 1; + shtab[shstrtab_shndx].sh_entsize = 0; + offset += (shstrtab.nrbytes + 3) & ~3; + } + + /* offset is now the offset of the section header table, which is last in the file */ + } else + offset = 0; + + ehdr.e_wident[0] = (((pdp10_uint36_t)ELFMAG0 << 28) + | (ELFMAG1 << 20) + | (ELFMAG2 << 12) + | (ELFMAG3 << 4) + | (ELFCLASS36 >> 4)); + ehdr.e_wident[1] = (((pdp10_uint36_t)(ELFCLASS36 & 0x0f) << 32) + | (ELFDATA2MSB << 24) + | (EV_CURRENT << 16) + | (ELFOSABI_NONE << 8) + | 0); /* EI_ABIVERSION */ + ehdr.e_wident[2] = 0; + ehdr.e_wident[3] = 0; + ehdr.e_type = ET_REL; + ehdr.e_machine = EM_PDP10; + ehdr.e_version = EV_CURRENT; + ehdr.e_entry = 0; + ehdr.e_phoff = 0; + ehdr.e_shoff = offset; + ehdr.e_flags = 0; + ehdr.e_ehsize = ELF36_EHDR_SIZEOF; + ehdr.e_phentsize = 0; + ehdr.e_phnum = 0; + ehdr.e_shentsize = ELF36_SHDR_SIZEOF; + ehdr.e_shnum = shnum; + ehdr.e_shstrndx = shstrtab_shndx; + + pdp10fp = pdp10_fopen(outfile, "wb"); + if (!pdp10fp) { + fprintf(stderr, "%s: failed to open %s: %s\n", progname, outfile, strerror(errno)); + return -1; + } + + if (pdp10_elf36_write_ehdr(pdp10fp, &ehdr) < 0) + return -1; + + if (text_shndx) + for (i = 0; i < aunit->text_nr_words; ++i) + if (pdp10_elf36_write_uint36(pdp10fp, aunit->text_words[i]) < 0) + return -1; + + if (symtab_shndx) + for (i = 0; i < symnum; ++i) + if (pdp10_elf36_write_sym(pdp10fp, &symtab[i]) < 0) + return -1; + + if (strtab_shndx) + if (strtab_write(pdp10fp, &strtab) < 0) + return -1; + + if (shstrtab_shndx) + if (strtab_write(pdp10fp, &shstrtab) < 0) + return -1; + + if (shnum) + for (i = 0; i < shnum; ++i) + if (pdp10_elf36_write_shdr(pdp10fp, &shtab[i]) < 0) + return -1; + + pdp10_fclose(pdp10fp); + return 0; +} diff --git a/as/output.h b/as/output.h new file mode 100644 index 0000000..a4f3a3d --- /dev/null +++ b/as/output.h @@ -0,0 +1,11 @@ +/* + * output.h + */ +#ifndef OUTPUT_H +#define OUTPUT_H + +#include "assemble.h" + +int output(const char *progname, struct aunit *aunit, const char *outfile); + +#endif /* OUTPUT_H */ diff --git a/as/parse.c b/as/parse.c new file mode 100644 index 0000000..b6dbe25 --- /dev/null +++ b/as/parse.c @@ -0,0 +1,354 @@ +/* + * parse.c + */ +#include +#include +#include +#include "pdp10-opcodes.h" +#include "input.h" /* for struct stmt */ +#include "scan.h" +#include "token.h" + +static int error(struct scan_state *scan_state, const char *msg, enum token token, const union token_attribute *token_attr) +{ + fprintf(stderr, "%s: %s line %u: syntax error: %s; current token is ", + scan_state->progname, scan_state->filename, scan_state->linenr, msg); + token_print(stderr, token, token_attr); + fprintf(stderr, "\n"); + return -1; +} + +static int parse_dot_globl(struct scan_state *scan_state, struct stmt *stmt) +{ + enum token token; + union token_attribute token_attr; + + token = scan_token(scan_state, &token_attr); + if (token == T_SYMBOL) { + stmt->u.symbol.name = token_attr.text; + token = scan_token(scan_state, &token_attr); + if (token == T_NEWLINE) { + stmt->tag = S_DOT_GLOBL; + return 1; + } + } + return error(scan_state, "junk after .globl directive", token, &token_attr); +} + +static int parse_dot_text(struct scan_state *scan_state, struct stmt *stmt) +{ + enum token token; + union token_attribute token_attr; + + token = scan_token(scan_state, &token_attr); + if (token == T_NEWLINE) { + stmt->tag = S_DOT_TEXT; + return 1; + } + return error(scan_state, "junk after .text directive", token, &token_attr); +} + +/* + * Recognize: + * + *