diff --git a/TODO b/TODO index d307297..0f75ce4 100644 --- a/TODO +++ b/TODO @@ -43,9 +43,8 @@ Tools: - readelf: add support for relocs - readelf: add support for program headers - as: - * support .ident: - + have .ident append string to .comment strtab - + finalize .comment strtab before output() + * tunit_{strtab_,}section_enter() should be generalized and merged + * what happens if user defines .comment as say text, and later enters .ident? * add support for named sections * add support for sub-sections * add support for data directives (.word, .asciz, etc) diff --git a/as/input.c b/as/input.c index 6022e82..a0683a4 100644 --- a/as/input.c +++ b/as/input.c @@ -87,6 +87,30 @@ static int do_dot_globl(struct scan_state *scan_state, struct tunit *tunit, stru return 0; } +static int do_dot_ident(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt) +{ + struct strtab *strtab; + + strtab = tunit_strtab_section_enter(tunit, ".comment"); + if (!strtab) + return -1; + + if (strtab->section.sh_type == SHT_NULL) { + /* The ELF specification doesn't specify attribute values for .comment + * sections, apart from sh_type, but GNU binutils formats them as string + * tables with the following attribute values. + */ + strtab->section.sh_type = SHT_PROGBITS; + strtab->section.sh_flags = SHF_MERGE | SHF_STRINGS; + strtab->section.sh_entsize = 1; + strtab->section.sh_addralign = 1; + } + + (void)strtab_enter(tunit, strtab, stmt->u.string.text); + + return 0; +} + static int do_dot_size(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt) { struct symbol *symbol; @@ -198,6 +222,8 @@ static int interpret(struct scan_state *scan_state, struct tunit *tunit, struct return do_dot_file(scan_state, tunit, stmt); case S_DOT_GLOBL: return do_dot_globl(scan_state, tunit, stmt); + case S_DOT_IDENT: + return do_dot_ident(scan_state, tunit, stmt); case S_DOT_SIZE: return do_dot_size(scan_state, tunit, stmt); case S_DOT_TEXT: diff --git a/as/parse.c b/as/parse.c index 2854dbe..ba91974 100644 --- a/as/parse.c +++ b/as/parse.c @@ -35,7 +35,7 @@ static int error(struct scan_state *scan_state, const char *msg, enum token toke return -1; } -static int parse_dot_file(struct scan_state *scan_state, struct stmt *stmt) +static int parse_dot_file_or_ident(struct scan_state *scan_state, struct stmt *stmt, enum stmt_tag tag, const char *errmsg) { enum token token; union token_attribute token_attr; @@ -45,11 +45,21 @@ static int parse_dot_file(struct scan_state *scan_state, struct stmt *stmt) stmt->u.string.text = token_attr.text; token = scan_token(scan_state, &token_attr); if (token == T_NEWLINE) { - stmt->tag = S_DOT_FILE; + stmt->tag = tag; return 1; } } - return error(scan_state, "junk after .file directive", token, &token_attr); + return error(scan_state, errmsg, token, &token_attr); +} + +static int parse_dot_file(struct scan_state *scan_state, struct stmt *stmt) +{ + return parse_dot_file_or_ident(scan_state, stmt, S_DOT_FILE, "junk after .file directive"); +} + +static int parse_dot_ident(struct scan_state *scan_state, struct stmt *stmt) +{ + return parse_dot_file_or_ident(scan_state, stmt, S_DOT_IDENT, "junk after .ident directive"); } static int parse_dot_globl(struct scan_state *scan_state, struct stmt *stmt) @@ -428,6 +438,8 @@ int parse_stmt(struct scan_state *scan_state, struct stmt *stmt) return parse_dot_file(scan_state, stmt); case T_DOT_GLOBL: return parse_dot_globl(scan_state, stmt); + case T_DOT_IDENT: + return parse_dot_ident(scan_state, stmt); case T_DOT_SIZE: return parse_dot_size(scan_state, stmt); case T_DOT_TEXT: diff --git a/as/token.def b/as/token.def index 2ab146d..8c472f6 100644 --- a/as/token.def +++ b/as/token.def @@ -25,6 +25,7 @@ /* reserved symbols including directives; MUST come first and MUST be listed in increasing alphanumeric order */ TOKEN(T_DOT_FILE, ".file", TAFMT_NONE) TOKEN(T_DOT_GLOBL, ".globl", TAFMT_NONE) +TOKEN(T_DOT_IDENT, ".ident", TAFMT_NONE) TOKEN(T_DOT_SIZE, ".size", TAFMT_NONE) TOKEN(T_DOT_TEXT, ".text", TAFMT_NONE) TOKEN(T_DOT_TYPE, ".type", TAFMT_NONE) @@ -57,7 +58,6 @@ TOKEN(T_DOT_BYTE, ".byte", TAFMT_NONE) TOKEN(T_DOT_COMM, ".comm", TAFMT_NONE) TOKEN(T_DOT_DATA, ".data", TAFMT_NONE) TOKEN(T_DOT_HIDDEN, ".hidden", TAFMT_NONE) -TOKEN(T_DOT_IDENT, ".ident", TAFMT_NONE) TOKEN(T_DOT_INTERNAL, ".internal", TAFMT_NONE) TOKEN(T_DOT_LOCAL, ".local", TAFMT_NONE) TOKEN(T_DOT_LONG, ".long", TAFMT_NONE) diff --git a/as/tunit.c b/as/tunit.c index 9aa2541..f32d0e6 100644 --- a/as/tunit.c +++ b/as/tunit.c @@ -190,6 +190,39 @@ void strtab_init(struct strtab *strtab, const char *name) strtab->head = NULL; } +static struct strtab *strtab_from_hashnode(const struct hashnode *hashnode) +{ + return hashnode ? container_of(hashnode, struct strtab, section.hashnode) : NULL; +} + +/* XXX: generalize and merge with tunit_section_enter() */ +struct strtab *tunit_strtab_section_enter(struct tunit *tunit, const char *name) +{ + uintptr_t hashval; + struct strtab *strtab; + + hashval = string_hash(name); + strtab = strtab_from_hashnode(hashtab_lookup(&tunit->sections, hashval, name)); + if (strtab) + return strtab; + + strtab = malloc(sizeof *strtab); + if (!strtab) { + fprintf(stderr, "%s: %s: malloc(%zu) failed: %s\n", tunit->progname, __FUNCTION__, sizeof *strtab, strerror(errno)); + return NULL; + } + + strtab_init(strtab, name); + /* XXX: undo stuff strtab_init() did which breaks .ident */ + strtab->section.sh_type = SHT_NULL; + + strtab->section.hashnode.hashval = hashval; + if (hashtab_insert(&tunit->sections, &strtab->section.hashnode) < 0) + return NULL; + + return strtab; +} + /* * Symbols hash table. */ diff --git a/as/tunit.h b/as/tunit.h index ad5737b..7c0c1a5 100644 --- a/as/tunit.h +++ b/as/tunit.h @@ -35,6 +35,7 @@ enum stmt_tag { /* directives */ S_DOT_FILE, S_DOT_GLOBL, + S_DOT_IDENT, S_DOT_SIZE, S_DOT_TEXT, S_DOT_TYPE_FUNCTION, @@ -47,7 +48,7 @@ struct stmt { struct stmt *next; enum stmt_tag tag; union { - struct { /* S_DOT_FILE */ + struct { /* S_DOT_FILE, S_DOT_IDENT */ const char *text; /* XXX: should be pdp10_uint9_t* */ } string; struct { /* S_DOT_GLOBL, S_LABEL, S_DOT_SIZE, S_DOT_TYPE_FUNCTION */ @@ -63,6 +64,16 @@ struct stmt { } u; }; +/* + * Sections. + * + * There are several kinds of sections: + * - generic sections with an image array + * these contain instructions or initialized data + * - strtab sections + * these contain a strtab and a specialised ->output() method + */ + struct section { struct hashnode hashnode; const char *name; @@ -80,8 +91,6 @@ struct section { Elf36_Word sh_entsize; /* assigned during output */ }; -void section_init(struct section *section, const char *name); - struct strtab_entry { struct strtab_entry *next; const char *string; @@ -119,13 +128,17 @@ struct tunit { int tunit_init(struct tunit *tunit, const char *progname); void tunit_fini(struct tunit *tunit); + +void section_init(struct section *section, const char *name); struct section *tunit_section_enter(struct tunit *tunit, const char *name); +struct strtab *tunit_strtab_section_enter(struct tunit *tunit, const char *name); + +void strtab_init(struct strtab *strtab, const char *name); +pdp10_uint36_t strtab_enter(struct tunit *tunit, struct strtab *strtab, const char *name); + struct symbol *tunit_symbol_lookup(struct tunit *tunit, const char *name); struct symbol *tunit_symbol_enter(struct tunit *tunit, const char *name); -pdp10_uint36_t strtab_enter(struct tunit *tunit, struct strtab *strtab, const char *name); -void strtab_init(struct strtab *strtab, const char *name); - /** * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member.