diff options
author | H. Peter Anvin <hpa@linux.intel.com> | 2016-02-16 12:39:26 -0800 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2016-02-16 12:39:26 -0800 |
commit | d1da074b837cd8f56f2eca3e622cdfe2de20dbec (patch) | |
tree | 88544296eaebab563d51180c4d0d029f114420a5 | |
parent | 615ef1a6f848d33cf90f70c77e7934fbd56fcd42 (diff) | |
download | nasm-d1da074b837cd8f56f2eca3e622cdfe2de20dbec.tar.gz |
outmacho: Allow arbitrary MachO sections, avoid bss lookup
Allow specifying sections with arbitary MachO segment and section
names, as opposed to having a fixed list of supported sections
(especially __DATA,__const is wrong in some cases.) Furthermore,
we do a completely unnecessary lookup of the bss section *for every
call to macho_output()* which is just plain crazy.
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r-- | output/outmacho.c | 259 |
1 files changed, 151 insertions, 108 deletions
diff --git a/output/outmacho.c b/output/outmacho.c index f8122f05..e39d655f 100644 --- a/output/outmacho.c +++ b/output/outmacho.c @@ -289,29 +289,6 @@ static struct section *get_section_by_index(const int32_t index) return s; } -static int32_t get_section_index_by_name(const char *segname, - const char *sectname) -{ - struct section *s; - - for (s = sects; s != NULL; s = s->next) - if (!strcmp(s->segname, segname) && !strcmp(s->sectname, sectname)) - return s->index; - - return -1; -} - -static char *get_section_name_by_index(const int32_t index) -{ - struct section *s; - - for (s = sects; s != NULL; s = s->next) - if (index == s->index) - return s->sectname; - - return NULL; -} - static uint8_t get_section_fileindex_by_index(const int32_t index) { struct section *s; @@ -467,9 +444,10 @@ static void macho_output(int32_t secto, const void *data, enum out_type type, uint64_t size, int32_t section, int32_t wrt) { - struct section *s, *sbss; + struct section *s; int64_t addr; uint8_t mydata[16], *p, gotload; + bool is_bss; if (secto == NO_SEG) { if (type != OUT_RESERVE) @@ -488,14 +466,14 @@ static void macho_output(int32_t secto, const void *data, /* should never happen */ if (s == NULL) - nasm_error(ERR_PANIC, "text section not found"); + nasm_panic(0, "text section not found"); } - sbss = get_section_by_name("__DATA", "__bss"); + is_bss = (s->flags & SECTION_TYPE) == S_ZEROFILL; - if (s == sbss && type != OUT_RESERVE) { - nasm_error(ERR_WARNING, "attempt to initialize memory in the" - " BSS section: ignored"); + if (is_bss && type != OUT_RESERVE) { + nasm_error(ERR_WARNING, "attempt to initialize memory in " + "BSS section: ignored"); s->size += realsize(type, size); return; } @@ -504,10 +482,9 @@ static void macho_output(int32_t secto, const void *data, switch (type) { case OUT_RESERVE: - if (s != sbss) { + if (!is_bss) { nasm_error(ERR_WARNING, "uninitialized space declared in" - " %s section: zeroing", - get_section_name_by_index(secto)); + " %s,%s section: zeroing", s->segname, s->sectname); sect_write(s, NULL, size); } else @@ -517,7 +494,7 @@ static void macho_output(int32_t secto, const void *data, case OUT_RAWDATA: if (section != NO_SEG) - nasm_error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); + nasm_panic(0, "OUT_RAWDATA with other than NO_SEG"); sect_write(s, data, size); break; @@ -533,7 +510,8 @@ static void macho_output(int32_t secto, const void *data, " section base references"); } else if (wrt == NO_SEG) { if (fmt->ptrsize == 8 && asize != 8) { - nasm_error(ERR_NONFATAL, "Mach-O 64-bit format does not support" + nasm_error(ERR_NONFATAL, + "Mach-O 64-bit format does not support" " 32-bit absolute addresses"); } else { add_reloc(s, section, RL_ABS, asize); @@ -622,6 +600,11 @@ static int32_t macho_section(char *name, int pass, int *bits) char *sectionAttributes; struct sectmap *sm; struct section *s; + const char *section, *segment; + uint32_t flags; + char *currentAttribute; + char *comma; + bool new_seg; (void)pass; @@ -635,84 +618,144 @@ static int32_t macho_section(char *name, int pass, int *bits) name = nasm_strsep(§ionAttributes, " \t"); } - for (sm = sectmap; sm->nasmsect != NULL; ++sm) { - /* make lookup into section name translation table */ - if (!strcmp(name, sm->nasmsect)) { - char *currentAttribute; - - /* try to find section with that name */ - index = get_section_index_by_name(sm->segname, sm->sectname); - - /* create it if it doesn't exist yet */ - if (index == -1) { - s = *sectstail = nasm_malloc(sizeof(struct section)); - s->next = NULL; - sectstail = &s->next; - - s->data = saa_init(1L); - s->index = seg_alloc(); - s->relocs = NULL; - s->align = -1; - s->pad = -1; - s->offset = -1; - - xstrncpy(s->segname, sm->segname); - xstrncpy(s->sectname, sm->sectname); - s->size = 0; - s->nreloc = 0; - s->flags = sm->flags; - - index = s->index; - } else { - s = get_section_by_index(index); - } + section = segment = NULL; + flags = 0; - while ((NULL != sectionAttributes) - && (currentAttribute = nasm_strsep(§ionAttributes, " \t"))) { - if (0 != *currentAttribute) { - if (!nasm_strnicmp("align=", currentAttribute, 6)) { - char *end; - int newAlignment, value; - - value = strtoul(currentAttribute + 6, (char**)&end, 0); - newAlignment = alignlog2_32(value); - - if (0 != *end) { - nasm_error(ERR_FATAL, - "unknown or missing alignment value \"%s\" " - "specified for section \"%s\"", - currentAttribute + 6, - name); - return NO_SEG; - } else if (0 > newAlignment) { - nasm_error(ERR_FATAL, - "alignment of %d (for section \"%s\") is not " - "a power of two", - value, - name); - return NO_SEG; - } - - if (s->align < newAlignment) - s->align = newAlignment; - } else if (!nasm_stricmp("data", currentAttribute)) { - /* Do nothing; 'data' is implicit */ - } else { - nasm_error(ERR_FATAL, - "unknown section attribute %s for section %s", - currentAttribute, - name); - return NO_SEG; - } - } - } + comma = strchr(name, ','); + if (comma) { + int len; - return index; - } + *comma = '\0'; + segment = name; + section = comma+1; + + len = strlen(segment); + if (len == 0) { + nasm_error(ERR_NONFATAL, "empty segment name\n"); + } else if (len > 16) { + nasm_error(ERR_NONFATAL, "segment name %s too long\n", segment); + } + + len = strlen(section); + if (len == 0) { + nasm_error(ERR_NONFATAL, "empty section name\n"); + } else if (len > 16) { + nasm_error(ERR_NONFATAL, "section name %s too long\n", section); + } + + if (!strcmp(segment, "__TEXT")) { + flags = S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | + S_ATTR_PURE_INSTRUCTIONS; + } else if (!strcmp(segment, "__DATA") && !strcmp(section, "__bss")) { + flags = S_ZEROFILL; + } else { + flags = S_REGULAR; + } + } else { + for (sm = sectmap; sm->nasmsect != NULL; ++sm) { + /* make lookup into section name translation table */ + if (!strcmp(name, sm->nasmsect)) { + segment = sm->segname; + section = sm->sectname; + goto found; + } + } + nasm_error(ERR_NONFATAL, "unknown section name\n"); + return NO_SEG; + } + + found: + /* try to find section with that name */ + s = get_section_by_name(segment, section); + + /* create it if it doesn't exist yet */ + if (!s) { + new_seg = true; + + s = *sectstail = nasm_malloc(sizeof(struct section)); + s->next = NULL; + sectstail = &s->next; + + s->data = saa_init(1L); + s->index = seg_alloc(); + s->relocs = NULL; + s->align = -1; + s->pad = -1; + s->offset = -1; + + xstrncpy(s->segname, segment); + xstrncpy(s->sectname, section); + s->size = 0; + s->nreloc = 0; + s->flags = flags; + + index = s->index; + } else { + new_seg = false; + } + + if (comma) + *comma = ','; /* Restore comma */ + + flags = (uint32_t)-1; + + while ((NULL != sectionAttributes) + && (currentAttribute = nasm_strsep(§ionAttributes, " \t"))) { + if (0 != *currentAttribute) { + if (!nasm_strnicmp("align=", currentAttribute, 6)) { + char *end; + int newAlignment, value; + + value = strtoul(currentAttribute + 6, (char**)&end, 0); + newAlignment = alignlog2_32(value); + + if (0 != *end) { + nasm_error(ERR_FATAL, + "unknown or missing alignment value \"%s\" " + "specified for section \"%s\"", + currentAttribute + 6, + name); + return NO_SEG; + } else if (0 > newAlignment) { + nasm_error(ERR_FATAL, + "alignment of %d (for section \"%s\") is not " + "a power of two", + value, + name); + return NO_SEG; + } + + if (s->align < newAlignment) + s->align = newAlignment; + } else if (!nasm_stricmp("data", currentAttribute)) { + flags = S_REGULAR; + } else if (!nasm_stricmp("code", currentAttribute)) { + flags = S_REGULAR | S_ATTR_SOME_INSTRUCTIONS | + S_ATTR_PURE_INSTRUCTIONS; + } else if (!nasm_stricmp("mixed", currentAttribute)) { + flags = S_REGULAR | S_ATTR_SOME_INSTRUCTIONS; + } else if (!nasm_stricmp("bss", currentAttribute)) { + flags = S_ZEROFILL; + } else { + nasm_error(ERR_NONFATAL, + "unknown section attribute %s for section %s", + currentAttribute, + name); + } + } + + if (flags != (uint32_t)-1) { + if (!new_seg && s->flags != flags) { + nasm_error(ERR_NONFATAL, + "inconsistent section attributes for section %s\n", + name); + } else { + s->flags = flags; + } + } } - nasm_error(ERR_FATAL, "invalid section name %s", name); - return NO_SEG; + return index; } static void macho_symdef(char *name, int32_t section, int64_t offset, |