From a485fbdd37d213aa81bbfc31ff411264d322252e Mon Sep 17 00:00:00 2001 From: Eric Christopher Date: Fri, 7 Oct 2005 22:30:56 +0000 Subject: Added section attributes, in particular S_ATTR_SOME_INSTRUCTIONS and update .text. Change symbols from saa to explicitly allocated. macho_layout_symbols: new function to sort symbols and renumber. adjust symtab output accordingly fixup relocs after renumbering add relocation debugging routines. --- output/outmacho.c | 316 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 281 insertions(+), 35 deletions(-) diff --git a/output/outmacho.c b/output/outmacho.c index eee2ea8f..caf234fa 100644 --- a/output/outmacho.c +++ b/output/outmacho.c @@ -66,13 +66,22 @@ struct section { #define S_REGULAR (0x0) /* standard section */ #define S_ZEROFILL (0x1) /* zerofill, in-memory only */ +#define SECTION_ATTRIBUTES_SYS 0x00ffff00 /* system setable attributes */ +#define S_ATTR_SOME_INSTRUCTIONS 0x00000400 /* section contains some + machine instructions */ +#define S_ATTR_EXT_RELOC 0x00000200 /* section has external + relocation entries */ +#define S_ATTR_LOC_RELOC 0x00000100 /* section has local + relocation entries */ + + static struct sectmap { const char *nasmsect; const char *segname; const char *sectname; const long flags; } sectmap[] = { { -".text", "__TEXT", "__text", S_REGULAR}, { +".text", "__TEXT", "__text", S_REGULAR|S_ATTR_SOME_INSTRUCTIONS}, { ".data", "__DATA", "__data", S_REGULAR}, { ".bss", "__DATA", "__bss", S_ZEROFILL}, { NULL, NULL, NULL}}; @@ -84,19 +93,27 @@ struct reloc { /* data that goes into the file */ long addr; /* op's offset in section */ unsigned int snum:24, /* contains symbol index if - ** ext otherwise in-file - ** section number */ - pcrel:1, /* relative relocation */ - length:2, /* 0=byte, 1=word, 2=long */ - ext:1, /* external symbol referenced */ - type:4; /* reloc type, 0 for us */ + ** ext otherwise in-file + ** section number */ + pcrel:1, /* relative relocation */ + length:2, /* 0=byte, 1=word, 2=long */ + ext:1, /* external symbol referenced */ + type:4; /* reloc type, 0 for us */ }; #define R_ABS 0 /* absolute relocation */ #define R_SCATTERED 0x80000000 /* reloc entry is scattered if - ** highest bit == 1 */ + ** highest bit == 1 */ struct symbol { + /* nasm internal data */ + struct symbol *next; /* next symbol in the list */ + char *name; /* name of this symbol */ + long initial_snum; /* symbol number used above in + reloc */ + long snum; /* true snum for reloc */ + + /* data that goes into the file */ long strx; /* string table index */ unsigned char type; /* symbol type */ unsigned char sect; /* NO_SECT or section number */ @@ -110,7 +127,7 @@ struct symbol { #define N_UNDF 0x0 /* undefined symbol | n_sect == */ #define N_ABS 0x2 /* absolute symbol | NO_SECT */ #define N_SECT 0xe /* defined symbol, n_sect holds - ** section number */ + ** section number */ #define N_TYPE 0x0e /* type bit mask */ @@ -119,8 +136,32 @@ struct symbol { #define MAX_SECT 255 /* maximum number of sections */ static struct section *sects, **sectstail; -static struct SAA *syms; +static struct symbol *syms, **symstail; static unsigned long nsyms; + +/* These variables are set by macho_layout_symbols() to organize + the symbol table and string table in order the dynamic linker + expects. They are then used in macho_write() to put out the + symbols and strings in that order. + + The order of the symbol table is: + local symbols + defined external symbols (sorted by name) + undefined external symbols (sorted by name) + + The order of the string table is: + strings for external symbols + strings for local symbols + */ +static unsigned long ilocalsym = 0; +static unsigned long iextdefsym = 0; +static unsigned long iundefsym = 0; +static unsigned long nlocalsym; +static unsigned long nextdefsym; +static unsigned long nundefsym; +static struct symbol **extdefsyms = NULL; +static struct symbol **undefsyms = NULL; + static struct RAA *extsyms; static struct SAA *strs; static unsigned long strslen; @@ -141,17 +182,20 @@ unsigned long seg_nsects = 0; unsigned long rel_padcnt = 0; -#define xstrncpy(xdst, xsrc) \ - memset(xdst, '\0', sizeof(xdst)); /* zero out whole buffer */ \ - strncpy(xdst, xsrc, sizeof(xdst)); /* copy over string */ \ +#define xstrncpy(xdst, xsrc) \ + memset(xdst, '\0', sizeof(xdst)); /* zero out whole buffer */ \ + strncpy(xdst, xsrc, sizeof(xdst)); /* copy over string */ \ xdst[sizeof(xdst) - 1] = '\0'; /* proper null-termination */ -#define align(x, y) \ +#define align(x, y) \ (((x) + (y) - 1) & ~((y) - 1)) /* align x to multiple of y */ -#define alignlong(x) \ +#define alignlong(x) \ align(x, sizeof(long)) /* align x to long boundary */ +static void debug_reloc (struct reloc *); +static void debug_section_relocs (struct section *) __attribute__ ((unused)); + static struct section *get_section_by_name(const char *segname, const char *sectname) { @@ -228,8 +272,12 @@ static void macho_init(FILE * fp, efunc errfunc, ldfunc ldef, sects = NULL; sectstail = §s; - syms = saa_init((long)sizeof(struct symbol)); + syms = NULL; + symstail = &syms; nsyms = 0; + nlocalsym = 0; + nextdefsym = 0; + nundefsym = 0; extsyms = raa_init(); strs = saa_init(1L); @@ -265,7 +313,7 @@ static void add_reloc(struct section *sect, long section, sect->relocs = r; /* the current end of the section will be the symbol's address for - ** now, might have to be fixed by fixup_relocs() later on. make + ** now, might have to be fixed by macho_fixup_relocs() later on. make ** sure, we don't make the symbol scattered by setting the highest ** bit by accident */ r->addr = sect->size & ~R_SCATTERED; @@ -497,12 +545,16 @@ static void macho_symdef(char *name, long section, long offset, return; } - sym = saa_wstruct(syms); + sym = *symstail = nasm_malloc(sizeof(struct symbol)); + sym->next = NULL; + symstail = &sym->next; + sym->name = name; sym->strx = strslen; sym->type = 0; sym->desc = 0; sym->value = offset; + sym->initial_snum = -1; /* external and common symbols get N_EXT */ if (is_global != 0) @@ -523,7 +575,8 @@ static void macho_symdef(char *name, long section, long offset, ** symbols, this works because every external symbol gets ** its own section number allocated internally by nasm and ** can so be used as a key */ - extsyms = raa_write(extsyms, section, nsyms); + extsyms = raa_write(extsyms, section, nsyms); + sym->initial_snum = nsyms; switch (is_global) { case 1: @@ -544,10 +597,6 @@ static void macho_symdef(char *name, long section, long offset, } } - /* append symbol name to string table */ - saa_wbytes(strs, name, (long)(strlen(name) + 1)); - strslen += strlen(name) + 1; - ++nsyms; } @@ -573,6 +622,108 @@ static const char *macho_stdmac[] = { NULL }; +/* Comparison function for qsort symbol layout. */ +static int layout_compare (const struct symbol **s1, + const struct symbol **s2) +{ + return (strcmp ((*s1)->name, (*s2)->name)); +} + +/* The native assembler does a few things in a similar function + + * Remove temporary labels + * Sort symbols according to local, external, undefined (by name) + * Order the string table + + We do not remove temporary labels right now. + + numsyms is the total number of symbols we have. strtabsize is the + number entries in the string table. */ + +static void macho_layout_symbols (unsigned long *numsyms, + unsigned long *strtabsize) +{ + struct symbol *sym, **symp; + unsigned long i,j; + + *numsyms = 0; + *strtabsize = sizeof (char); + + symp = &syms; + + while ((sym = *symp)) { + /* Undefined symbols are now external. */ + if (sym->type == N_UNDF) + sym->type |= N_EXT; + + if ((sym->type & N_EXT) == 0) { + sym->snum = *numsyms; + *numsyms = *numsyms + 1; + nlocalsym++; + } + else { + if ((sym->type & N_TYPE) != N_UNDF) + nextdefsym++; + else + nundefsym++; + + /* If we handle debug info we'll want + to check for it here instead of just + adding the symbol to the string table. */ + sym->strx = *strtabsize; + saa_wbytes (strs, sym->name, (long)(strlen(sym->name) + 1)); + *strtabsize += strlen(sym->name) + 1; + } + symp = &(sym->next); + } + + /* Next, sort the symbols. Most of this code is a direct translation from + the Apple cctools symbol layout. We need to keep compatibility with that. */ + /* Set the indexes for symbol groups into the symbol table */ + ilocalsym = 0; + iextdefsym = nlocalsym; + iundefsym = nlocalsym + nextdefsym; + + /* allocate arrays for sorting externals by name */ + extdefsyms = nasm_malloc(nextdefsym * sizeof(struct symbol *)); + undefsyms = nasm_malloc(nundefsym * sizeof(struct symbol *)); + + i = 0; + j = 0; + + symp = &syms; + + while ((sym = *symp)) { + + if((sym->type & N_EXT) == 0) { + sym->strx = *strtabsize; + saa_wbytes (strs, sym->name, (long)(strlen (sym->name) + 1)); + *strtabsize += strlen(sym->name) + 1; + } + else { + if((sym->type & N_TYPE) != N_UNDF) + extdefsyms[i++] = sym; + else + undefsyms[j++] = sym; + } + symp = &(sym->next); + } + + qsort(extdefsyms, nextdefsym, sizeof(struct symbol *), + (int (*)(const void *, const void *))layout_compare); + qsort(undefsyms, nundefsym, sizeof(struct symbol *), + (int (*)(const void *, const void *))layout_compare); + + for(i = 0; i < nextdefsym; i++) { + extdefsyms[i]->snum = *numsyms; + *numsyms += 1; + } + for(j = 0; j < nundefsym; j++) { + undefsyms[j]->snum = *numsyms; + *numsyms += 1; + } +} + /* Calculate some values we'll need for writing later. */ static void macho_calculate_sizes (void) @@ -772,28 +923,84 @@ static void macho_write_symtab (void) { struct symbol *sym; struct section *s; - long fi, i; + long fi; + long i; /* we don't need to pad here since MACHO_RELINFO_SIZE == 8 */ - saa_rewind(syms); - for (i = 0; i < nsyms; ++i) { - sym = saa_rstruct(syms); + for (sym = syms; sym != NULL; sym = sym->next) { + if ((sym->type & N_EXT) == 0) { + fwritelong(sym->strx, machofp); /* string table entry number */ + fwrite(&sym->type, 1, 1, machofp); /* symbol type */ + fwrite(&sym->sect, 1, 1, machofp); /* section */ + fwriteshort(sym->desc, machofp); /* description */ + + /* Fix up the symbol value now that we know the final section + sizes. */ + if (((sym->type & N_TYPE) == N_SECT) && (sym->sect != NO_SECT)) { + for (s = sects, fi = 1; + s != NULL && fi < sym->sect; s = s->next, ++fi) + sym->value += s->size; + } + + fwritelong(sym->value, machofp); /* value (i.e. offset) */ + } + } - fwritelong(sym->strx, machofp); /* string table entry number */ - fwrite(&sym->type, 1, 1, machofp); /* symbol type */ - fwrite(&sym->sect, 1, 1, machofp); /* section */ - fwriteshort(sym->desc, machofp); /* description */ + for (i = 0; i < nextdefsym; i++) { + sym = extdefsyms[i]; + fwritelong(sym->strx, machofp); + fwrite(&sym->type, 1, 1, machofp); /* symbol type */ + fwrite(&sym->sect, 1, 1, machofp); /* section */ + fwriteshort(sym->desc, machofp); /* description */ - /* fix up the symbol value now we know the final section - ** sizes. */ + /* Fix up the symbol value now that we know the final section + sizes. */ if (((sym->type & N_TYPE) == N_SECT) && (sym->sect != NO_SECT)) { for (s = sects, fi = 1; s != NULL && fi < sym->sect; s = s->next, ++fi) sym->value += s->size; } - fwritelong(sym->value, machofp); /* value (i.e. offset) */ + fwritelong(sym->value, machofp); /* value (i.e. offset) */ + } + + for (i = 0; i < nundefsym; i++) { + sym = undefsyms[i]; + fwritelong(sym->strx, machofp); + fwrite(&sym->type, 1, 1, machofp); /* symbol type */ + fwrite(&sym->sect, 1, 1, machofp); /* section */ + fwriteshort(sym->desc, machofp); /* description */ + + /* Fix up the symbol value now that we know the final section + sizes. */ + if (((sym->type & N_TYPE) == N_SECT) && (sym->sect != NO_SECT)) { + for (s = sects, fi = 1; + s != NULL && fi < sym->sect; s = s->next, ++fi) + sym->value += s->size; + } + + fwritelong(sym->value, machofp); /* value (i.e. offset) */ + } +} + +/* Fixup the snum in the relocation entries, we should be + doing this only for externally undefined symbols. */ +static void macho_fixup_relocs (struct reloc *r) +{ + struct symbol *sym; + int i; + + while (r != NULL) { + if (r->ext) { + for (i = 0; i < nundefsym; i++) { + sym = undefsyms[i]; + if (sym->initial_snum == r->snum) { + r->snum = sym->snum; + } + } + } + r = r->next; } } @@ -921,9 +1128,18 @@ static void macho_cleanup(int debuginfo) { struct section *s; struct reloc *r; + struct symbol *sym; (void)debuginfo; + /* Sort all symbols. */ + macho_layout_symbols (&nsyms, &strslen); + + /* Fixup relocation entries */ + for (s = sects; s != NULL; s = s->next) { + macho_fixup_relocs (s->relocs); + } + /* First calculate and finalize needed values. */ macho_calculate_sizes(); macho_write(); @@ -948,7 +1164,37 @@ static void macho_cleanup(int debuginfo) saa_free(strs); raa_free(extsyms); - saa_free(syms); + + while (syms->next) { + sym = syms; + syms = syms->next; + + nasm_free (sym); + } +} + +/* Debugging routines. */ +static void debug_reloc (struct reloc *r) +{ + fprintf (stdout, "reloc:\n"); + fprintf (stdout, "\taddr: %ld\n", r->addr); + fprintf (stdout, "\tsnum: %d\n", r->snum); + fprintf (stdout, "\tpcrel: %d\n", r->pcrel); + fprintf (stdout, "\tlength: %d\n", r->length); + fprintf (stdout, "\text: %d\n", r->ext); + fprintf (stdout, "\ttype: %d\n", r->type); +} + +static void debug_section_relocs (struct section *s) +{ + struct reloc *r = s->relocs; + + fprintf (stdout, "relocs for section %s:\n\n", s->sectname); + + while (r != NULL) { + debug_reloc (r); + r = r->next; + } } struct ofmt of_macho = { -- cgit v1.2.1