0
0
mirror of https://github.com/netwide-assembler/nasm.git synced 2025-09-22 10:43:39 -04:00

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>
This commit is contained in:
H. Peter Anvin
2016-02-16 12:39:26 -08:00
parent 615ef1a6f8
commit d1da074b83

View File

@@ -289,29 +289,6 @@ static struct section *get_section_by_index(const int32_t index)
return s; 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) static uint8_t get_section_fileindex_by_index(const int32_t index)
{ {
struct section *s; struct section *s;
@@ -467,9 +444,10 @@ static void macho_output(int32_t secto, const void *data,
enum out_type type, uint64_t size, enum out_type type, uint64_t size,
int32_t section, int32_t wrt) int32_t section, int32_t wrt)
{ {
struct section *s, *sbss; struct section *s;
int64_t addr; int64_t addr;
uint8_t mydata[16], *p, gotload; uint8_t mydata[16], *p, gotload;
bool is_bss;
if (secto == NO_SEG) { if (secto == NO_SEG) {
if (type != OUT_RESERVE) if (type != OUT_RESERVE)
@@ -488,13 +466,13 @@ static void macho_output(int32_t secto, const void *data,
/* should never happen */ /* should never happen */
if (s == NULL) 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) { if (is_bss && type != OUT_RESERVE) {
nasm_error(ERR_WARNING, "attempt to initialize memory in the" nasm_error(ERR_WARNING, "attempt to initialize memory in "
"BSS section: ignored"); "BSS section: ignored");
s->size += realsize(type, size); s->size += realsize(type, size);
return; return;
@@ -504,10 +482,9 @@ static void macho_output(int32_t secto, const void *data,
switch (type) { switch (type) {
case OUT_RESERVE: case OUT_RESERVE:
if (s != sbss) { if (!is_bss) {
nasm_error(ERR_WARNING, "uninitialized space declared in" nasm_error(ERR_WARNING, "uninitialized space declared in"
" %s section: zeroing", " %s,%s section: zeroing", s->segname, s->sectname);
get_section_name_by_index(secto));
sect_write(s, NULL, size); sect_write(s, NULL, size);
} else } else
@@ -517,7 +494,7 @@ static void macho_output(int32_t secto, const void *data,
case OUT_RAWDATA: case OUT_RAWDATA:
if (section != NO_SEG) 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); sect_write(s, data, size);
break; break;
@@ -533,7 +510,8 @@ static void macho_output(int32_t secto, const void *data,
" section base references"); " section base references");
} else if (wrt == NO_SEG) { } else if (wrt == NO_SEG) {
if (fmt->ptrsize == 8 && asize != 8) { 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"); " 32-bit absolute addresses");
} else { } else {
add_reloc(s, section, RL_ABS, asize); add_reloc(s, section, RL_ABS, asize);
@@ -622,6 +600,11 @@ static int32_t macho_section(char *name, int pass, int *bits)
char *sectionAttributes; char *sectionAttributes;
struct sectmap *sm; struct sectmap *sm;
struct section *s; struct section *s;
const char *section, *segment;
uint32_t flags;
char *currentAttribute;
char *comma;
bool new_seg;
(void)pass; (void)pass;
@@ -635,16 +618,60 @@ static int32_t macho_section(char *name, int pass, int *bits)
name = nasm_strsep(&sectionAttributes, " \t"); name = nasm_strsep(&sectionAttributes, " \t");
} }
section = segment = NULL;
flags = 0;
comma = strchr(name, ',');
if (comma) {
int len;
*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) { for (sm = sectmap; sm->nasmsect != NULL; ++sm) {
/* make lookup into section name translation table */ /* make lookup into section name translation table */
if (!strcmp(name, sm->nasmsect)) { if (!strcmp(name, sm->nasmsect)) {
char *currentAttribute; 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 */ /* try to find section with that name */
index = get_section_index_by_name(sm->segname, sm->sectname); s = get_section_by_name(segment, section);
/* create it if it doesn't exist yet */ /* create it if it doesn't exist yet */
if (index == -1) { if (!s) {
new_seg = true;
s = *sectstail = nasm_malloc(sizeof(struct section)); s = *sectstail = nasm_malloc(sizeof(struct section));
s->next = NULL; s->next = NULL;
sectstail = &s->next; sectstail = &s->next;
@@ -656,17 +683,22 @@ static int32_t macho_section(char *name, int pass, int *bits)
s->pad = -1; s->pad = -1;
s->offset = -1; s->offset = -1;
xstrncpy(s->segname, sm->segname); xstrncpy(s->segname, segment);
xstrncpy(s->sectname, sm->sectname); xstrncpy(s->sectname, section);
s->size = 0; s->size = 0;
s->nreloc = 0; s->nreloc = 0;
s->flags = sm->flags; s->flags = flags;
index = s->index; index = s->index;
} else { } else {
s = get_section_by_index(index); new_seg = false;
} }
if (comma)
*comma = ','; /* Restore comma */
flags = (uint32_t)-1;
while ((NULL != sectionAttributes) while ((NULL != sectionAttributes)
&& (currentAttribute = nasm_strsep(&sectionAttributes, " \t"))) { && (currentAttribute = nasm_strsep(&sectionAttributes, " \t"))) {
if (0 != *currentAttribute) { if (0 != *currentAttribute) {
@@ -696,24 +728,35 @@ static int32_t macho_section(char *name, int pass, int *bits)
if (s->align < newAlignment) if (s->align < newAlignment)
s->align = newAlignment; s->align = newAlignment;
} else if (!nasm_stricmp("data", currentAttribute)) { } else if (!nasm_stricmp("data", currentAttribute)) {
/* Do nothing; 'data' is implicit */ 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 { } else {
nasm_error(ERR_FATAL, nasm_error(ERR_NONFATAL,
"unknown section attribute %s for section %s", "unknown section attribute %s for section %s",
currentAttribute, currentAttribute,
name); name);
return NO_SEG; }
}
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;
} }
} }
} }
return index; return index;
} }
}
nasm_error(ERR_FATAL, "invalid section name %s", name);
return NO_SEG;
}
static void macho_symdef(char *name, int32_t section, int64_t offset, static void macho_symdef(char *name, int32_t section, int64_t offset,
int is_global, char *special) int is_global, char *special)