diff options
author | H. Peter Anvin <hpa@linux.intel.com> | 2018-05-30 14:43:46 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2018-05-30 14:48:18 -0700 |
commit | 892c4818ceaddd53ab98ee4fecc3821dcc703751 (patch) | |
tree | a13338556a104dd4c3b66f36c9ec4175bdcf94e4 | |
parent | b7136487bd59b943645bbdc917b694340399ab9b (diff) | |
download | nasm-892c4818ceaddd53ab98ee4fecc3821dcc703751.tar.gz |
Add support for backend-defined subsections and label hacks
MachO has this odd thing called "subsections via symbols", by which a
symbol can magically start what effectively is a new section. To
support this, add support for a calldown into the backend when a new
symbol is defined *at the current output location*, and allow it to
switch the current segment.
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r-- | asm/directiv.c | 3 | ||||
-rw-r--r-- | asm/labels.c | 33 | ||||
-rw-r--r-- | asm/nasm.c | 46 | ||||
-rw-r--r-- | asm/segalloc.c | 9 | ||||
-rw-r--r-- | include/nasm.h | 20 | ||||
-rw-r--r-- | include/nasmlib.h | 1 | ||||
-rw-r--r-- | output/nullout.c | 7 | ||||
-rw-r--r-- | output/outaout.c | 4 | ||||
-rw-r--r-- | output/outas86.c | 2 | ||||
-rw-r--r-- | output/outbin.c | 6 | ||||
-rw-r--r-- | output/outcoff.c | 6 | ||||
-rw-r--r-- | output/outdbg.c | 33 | ||||
-rw-r--r-- | output/outelf.c | 6 | ||||
-rw-r--r-- | output/outieee.c | 2 | ||||
-rw-r--r-- | output/outlib.h | 3 | ||||
-rw-r--r-- | output/outmacho.c | 50 | ||||
-rw-r--r-- | output/outobj.c | 2 | ||||
-rw-r--r-- | output/outrdf2.c | 2 |
18 files changed, 203 insertions, 32 deletions
diff --git a/asm/directiv.c b/asm/directiv.c index 7e646832..2f887647 100644 --- a/asm/directiv.c +++ b/asm/directiv.c @@ -251,9 +251,8 @@ bool process_directives(char *directive) nasm_error(pass0 < 2 ? ERR_NONFATAL : ERR_PANIC, "segment name `%s' not recognized", value); } else { - in_absolute = false; - location.segment = seg; globalbits = sb; + switch_segment(seg); } break; } diff --git a/asm/labels.c b/asm/labels.c index 1183151c..ce0df180 100644 --- a/asm/labels.c +++ b/asm/labels.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2017 The NASM Authors - All Rights Reserved + * Copyright 1996-2018 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -231,6 +231,32 @@ bool is_extern(const char *label) return (lptr && (lptr->defn.is_global & EXTERN_BIT)); } +static void handle_herelabel(const char *label, + int32_t *segment, int64_t *offset) +{ + int32_t oldseg; + + if (likely(!ofmt->herelabel)) + return; + + if (unlikely(location.segment == NO_SEG)) + return; + + oldseg = *segment; + + if (oldseg == location.segment && *offset == location.offset) { + /* This label is defined at this location */ + int32_t newseg; + + newseg = ofmt->herelabel(label, oldseg); + if (likely(newseg == oldseg)) + return; + + *segment = newseg; + *offset = switch_segment(newseg); + } +} + void redefine_label(char *label, int32_t segment, int64_t offset, char *special, bool is_norm, bool isextrn) { @@ -254,6 +280,8 @@ void redefine_label(char *label, int32_t segment, int64_t offset, char *special, label, segment, offset, special, is_norm, isextrn); #endif + handle_herelabel(label, &segment, &offset); + lptr = find_label(label, 1, &created); if (!lptr) nasm_panic(0, "can't find label `%s' on pass two", label); @@ -310,6 +338,9 @@ void define_label(char *label, int32_t segment, int64_t offset, char *special, nasm_error(ERR_DEBUG, "define_label (%s, %"PRIx32", %"PRIx64", %s, %d, %d)", label, segment, offset, special, is_norm, isextrn); #endif + + handle_herelabel(label, &segment, &offset); + lptr = find_label(label, 1, NULL); if (!lptr) return; @@ -153,9 +153,17 @@ static char *quote_for_pmake(const char *str); static char *quote_for_wmake(const char *str); static char *(*quote_for_make)(const char *) = quote_for_pmake; -static int64_t get_curr_offs(void) +int64_t switch_segment(int32_t segment) { - return in_absolute ? absolute.offset : raa_read(offsets, location.segment); + location.segment = segment; + if (segment == NO_SEG) { + location.offset = absolute.offset; + in_absolute = true; + } else { + location.offset = raa_read(offsets, segment); + in_absolute = false; + } + return location.offset; } static void set_curr_offs(int64_t l_off) @@ -166,6 +174,15 @@ static void set_curr_offs(int64_t l_off) offsets = raa_write(offsets, location.segment, l_off); } +static void increment_offset(int64_t delta) +{ + if (unlikely(delta == 0)) + return; + + location.offset += delta; + set_curr_offs(location.offset); +} + static void nasm_fputs(const char *line, FILE * outfile) { if (outfile) { @@ -1285,7 +1302,6 @@ static void assemble_file(const char *fname, StrList **depend_ptr) char *line; insn output_ins; int i; - int64_t offs; int pass_max; uint64_t prev_offset_changed; unsigned int stall_count = 0; /* Make sure we make forward progress... */ @@ -1326,22 +1342,25 @@ static void assemble_file(const char *fname, StrList **depend_ptr) } in_absolute = false; global_offset_changed = 0; /* set by redefine_label */ - location.segment = ofmt->section(NULL, pass2, &globalbits); + seg_alloc_reset(); if (passn > 1) { saa_rewind(forwrefs); forwref = saa_rstruct(forwrefs); raa_free(offsets); offsets = raa_init(); } + location.segment = NO_SEG; + location.offset = 0; + if (passn == 1) + location.known = true; + ofmt->reset(); + switch_segment(ofmt->section(NULL, pass2, &globalbits)); preproc->reset(fname, pass1, pass1 == 2 ? depend_ptr : NULL); /* Revert all warnings to the default state */ memcpy(warning_state, warning_state_init, sizeof warning_state); globallineno = 0; - if (passn == 1) - location.known = true; - location.offset = offs = get_curr_offs(); while ((line = preproc->getline())) { if (globallineno++ == GLOBALLINENO_MAX) @@ -1459,7 +1478,8 @@ static void assemble_file(const char *fname, StrList **depend_ptr) for (n = 1; n <= output_ins.times; n++) { if (pass1 == 1) { - int64_t l = insn_size(location.segment, offs, + int64_t l = insn_size(location.segment, + location.offset, globalbits, &output_ins); /* if (using_debug_info) && output_ins.opcode != -1) */ @@ -1542,8 +1562,7 @@ static void assemble_file(const char *fname, StrList **depend_ptr) * input file over and over. */ if (l != -1) { - offs += l; - set_curr_offs(offs); + increment_offset(l); } /* * else l == -1 => invalid instruction, which will be @@ -1552,9 +1571,9 @@ static void assemble_file(const char *fname, StrList **depend_ptr) } else { if (n == 2) lfmt->uplevel(LIST_TIMES); - offs += assemble(location.segment, offs, - globalbits, &output_ins); - set_curr_offs(offs); + increment_offset(assemble(location.segment, + location.offset, + globalbits, &output_ins)); } } /* not an EQU */ } @@ -1565,7 +1584,6 @@ static void assemble_file(const char *fname, StrList **depend_ptr) end_of_line: nasm_free(line); - location.offset = offs = get_curr_offs(); } /* end while (line = preproc->getline... */ if (pass0 == 2 && global_offset_changed && !terminate_after_phase) diff --git a/asm/segalloc.c b/asm/segalloc.c index 60596221..e81f919d 100644 --- a/asm/segalloc.c +++ b/asm/segalloc.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2016 The NASM Authors - All Rights Reserved + * Copyright 1996-2018 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -40,9 +40,14 @@ #include "nasmlib.h" #include "insns.h" +static int32_t next_seg = 0; +void seg_alloc_reset(void) +{ + next_seg = 0; +} + int32_t seg_alloc(void) { - static int32_t next_seg = 0; int32_t this_seg = next_seg; next_seg += 2; diff --git a/include/nasm.h b/include/nasm.h index a5a7b661..eb3691f7 100644 --- a/include/nasm.h +++ b/include/nasm.h @@ -819,6 +819,11 @@ struct ofmt { void (*init)(void); /* + * This procedure is called at the start of each pass. + */ + void (*reset)(void); + + /* * This is the modern output function, which gets passed * a struct out_data with much more information. See the * definition of struct out_data. @@ -892,6 +897,16 @@ struct ofmt { int32_t (*section)(char *name, int pass, int *bits); /* + * This function is called when a label is defined + * in the source code. It is allowed to change the section + * number as a result, but not the bits value. + * This is *only* called if the symbol defined is at the + * current offset, i.e. "foo:" or "foo equ $". + * The offset isn't passed; and may not be stable at this point. + */ + int32_t (*herelabel)(const char *name, int32_t seg); + + /* * This procedure is called to modify section alignment, * note there is a trick, the alignment can only increase */ @@ -1231,4 +1246,9 @@ extern int globalbnd; /* default to using bnd prefix? */ extern const char *inname; /* primary input filename */ extern const char *outname; /* output filename */ +/* + * Switch to a different segment and return the current offset + */ +int64_t switch_segment(int32_t segment); + #endif diff --git a/include/nasmlib.h b/include/nasmlib.h index a4f6bf95..c6ca3373 100644 --- a/include/nasmlib.h +++ b/include/nasmlib.h @@ -193,6 +193,7 @@ int64_t readstrnum(char *str, int length, bool *warn); /* * seg_alloc: allocate a hitherto unused segment number. */ +void seg_alloc_reset(void); int32_t seg_alloc(void); /* diff --git a/output/nullout.c b/output/nullout.c index 4eee5ef9..daf24f53 100644 --- a/output/nullout.c +++ b/output/nullout.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * Copyright 1996-2018 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -49,3 +49,8 @@ void null_sectalign(int32_t seg, unsigned int value) (void)seg; (void)value; } + +void null_reset(void) +{ + /* Nothing to do */ +} diff --git a/output/outaout.c b/output/outaout.c index 5dab46c0..184684a9 100644 --- a/output/outaout.c +++ b/output/outaout.c @@ -910,10 +910,12 @@ const struct ofmt of_aout = { &null_debug_form, aout_stdmac, aout_init, + null_reset, nasm_do_legacy_output, aout_out, aout_deflabel, aout_section_names, + NULL, null_sectalign, aout_segbase, null_directive, @@ -935,10 +937,12 @@ const struct ofmt of_aoutb = { &null_debug_form, aout_stdmac, aoutb_init, + null_reset, nasm_do_legacy_output, aout_out, aout_deflabel, aout_section_names, + NULL, null_sectalign, aout_segbase, null_directive, diff --git a/output/outas86.c b/output/outas86.c index 18781950..3f9867b9 100644 --- a/output/outas86.c +++ b/output/outas86.c @@ -622,10 +622,12 @@ const struct ofmt of_as86 = { &null_debug_form, as86_stdmac, as86_init, + null_reset, nasm_do_legacy_output, as86_out, as86_deflabel, as86_section_names, + NULL, null_sectalign, as86_segbase, null_directive, diff --git a/output/outbin.c b/output/outbin.c index 2c8a9da9..8a71a503 100644 --- a/output/outbin.c +++ b/output/outbin.c @@ -1638,10 +1638,12 @@ const struct ofmt of_bin = { &null_debug_form, bin_stdmac, bin_init, + null_reset, nasm_do_legacy_output, bin_out, bin_deflabel, bin_secname, + NULL, bin_sectalign, bin_segbase, bin_directive, @@ -1659,10 +1661,12 @@ const struct ofmt of_ith = { &null_debug_form, bin_stdmac, ith_init, + null_reset, nasm_do_legacy_output, bin_out, bin_deflabel, bin_secname, + NULL, bin_sectalign, bin_segbase, bin_directive, @@ -1680,10 +1684,12 @@ const struct ofmt of_srec = { &null_debug_form, bin_stdmac, srec_init, + null_reset, nasm_do_legacy_output, bin_out, bin_deflabel, bin_secname, + NULL, bin_sectalign, bin_segbase, bin_directive, diff --git a/output/outcoff.c b/output/outcoff.c index 54aed727..f7b62b80 100644 --- a/output/outcoff.c +++ b/output/outcoff.c @@ -1156,10 +1156,12 @@ const struct ofmt of_coff = { &null_debug_form, coff_stdmac, coff_std_init, + null_reset, nasm_do_legacy_output, coff_out, coff_deflabel, coff_section_names, + NULL, coff_sectalign, coff_segbase, coff_directives, @@ -1185,10 +1187,12 @@ const struct ofmt of_win32 = { &df_cv8, coff_stdmac, coff_win32_init, + null_reset, nasm_do_legacy_output, coff_out, coff_deflabel, coff_section_names, + NULL, coff_sectalign, coff_segbase, coff_directives, @@ -1212,10 +1216,12 @@ const struct ofmt of_win64 = { &df_cv8, coff_stdmac, coff_win64_init, + null_reset, nasm_do_legacy_output, coff_out, coff_deflabel, coff_section_names, + NULL, coff_sectalign, coff_segbase, coff_directives, diff --git a/output/outdbg.c b/output/outdbg.c index c57e0af0..87119cbd 100644 --- a/output/outdbg.c +++ b/output/outdbg.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2017 The NASM Authors - All Rights Reserved + * Copyright 1996-2018 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -60,6 +60,8 @@ struct Section { static unsigned long dbg_max_data_dump = 128; static bool section_labels = true; +static bool subsections_via_symbols = false; +static int32_t init_seg; const struct ofmt of_dbg; static void dbg_init(void) @@ -68,6 +70,12 @@ static void dbg_init(void) fprintf(ofile, "NASM Output format debug dump\n"); fprintf(ofile, "input file = %s\n", inname); fprintf(ofile, "output file = %s\n", outname); + init_seg = seg_alloc(); +} + +static void dbg_reset(void) +{ + fprintf(ofile, "*** pass reset: pass0 = %d, passn = %d\n", pass0, passn); } static void dbg_cleanup(void) @@ -93,8 +101,8 @@ static int32_t dbg_add_section(char *name, int pass, int *bits, *bits = 16; if (!name) { - fprintf(ofile, "section_name on init: returning %d\n", - seg = seg_alloc()); + fprintf(ofile, "section_name on init: returning %d\n", init_seg); + seg = init_seg; } else { int n = strcspn(name, " \t"); char *sname = nasm_strndup(name, n); @@ -127,6 +135,19 @@ static int32_t dbg_section_names(char *name, int pass, int *bits) return dbg_add_section(name, pass, bits, "section_names"); } +static int32_t dbg_herelabel(const char *name, int32_t seg) +{ + int32_t newseg = seg; + + if (subsections_via_symbols && name[0] != 'L') + newseg += 0x10000; + + fprintf(ofile, "herelabel %s (seg %08x) -> %08x\n", + name, seg, newseg); + + return newseg; +} + static void dbg_deflabel(char *name, int32_t segment, int64_t offset, int is_global, char *special) { @@ -363,7 +384,9 @@ dbg_pragma(const struct pragma *pragma) case D_NOSECLABELS: section_labels = false; break; - + case D_SUBSECTIONS_VIA_SYMBOLS: + subsections_via_symbols = true; + break; default: break; } @@ -447,10 +470,12 @@ const struct ofmt of_dbg = { &debug_debug_form, dbg_stdmac, dbg_init, + dbg_reset, dbg_out, dbg_legacy_out, dbg_deflabel, dbg_section_names, + dbg_herelabel, dbg_sectalign, dbg_segbase, dbg_directive, diff --git a/output/outelf.c b/output/outelf.c index 31a6ebdd..7cdf9a34 100644 --- a/output/outelf.c +++ b/output/outelf.c @@ -2274,10 +2274,12 @@ const struct ofmt of_elf32 = { &elf32_df_stabs, elf_stdmac, elf_init, + null_reset, nasm_do_legacy_output, elf32_out, elf_deflabel, elf_section_names, + NULL, elf_sectalign, elf_segbase, elf_directive, @@ -2324,10 +2326,12 @@ const struct ofmt of_elf64 = { &elf64_df_stabs, elf_stdmac, elf_init, + null_reset, nasm_do_legacy_output, elf64_out, elf_deflabel, elf_section_names, + NULL, elf_sectalign, elf_segbase, elf_directive, @@ -2374,10 +2378,12 @@ const struct ofmt of_elfx32 = { &elfx32_df_stabs, elf_stdmac, elf_init, + null_reset, nasm_do_legacy_output, elfx32_out, elf_deflabel, elf_section_names, + NULL, elf_sectalign, elf_segbase, elf_directive, diff --git a/output/outieee.c b/output/outieee.c index 8500f967..6e7360d1 100644 --- a/output/outieee.c +++ b/output/outieee.c @@ -1506,10 +1506,12 @@ const struct ofmt of_ieee = { &ladsoft_debug_form, NULL, ieee_init, + null_reset, nasm_do_legacy_output, ieee_out, ieee_deflabel, ieee_segment, + NULL, ieee_sectalign, ieee_segbase, ieee_directive, diff --git a/output/outlib.h b/output/outlib.h index a34c1382..664ca389 100644 --- a/output/outlib.h +++ b/output/outlib.h @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2016 The NASM Authors - All Rights Reserved + * Copyright 1996-2018 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -43,6 +43,7 @@ uint64_t realsize(enum out_type type, uint64_t size); enum directive_result null_directive(enum directive directive, char *value, int pass); void null_sectalign(int32_t seg, unsigned int value); +void null_reset(void); /* Do-nothing versions of all the debug routines */ void null_debug_init(void); diff --git a/output/outmacho.c b/output/outmacho.c index 83a76e98..38ead489 100644 --- a/output/outmacho.c +++ b/output/outmacho.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2017 The NASM Authors - All Rights Reserved + * Copyright 1996-2018 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -153,16 +153,17 @@ struct section { /* nasm internal data */ struct section *next; struct SAA *data; - int32_t index; + uint16_t index; /* Main section index */ + uint16_t subsection; /* Current subsection */ int32_t fileindex; struct reloc *relocs; struct rbtree *syms[2]; /* All/global symbols symbols in section */ int align; - bool by_name; /* This section was specified by full MachO name */ + bool by_name; /* This section was specified by full MachO name */ /* data that goes into the file */ - char sectname[16]; /* what this section is called */ - char segname[16]; /* segment this section will be in */ + char sectname[16]; /* what this section is called */ + char segname[16]; /* segment this section will be in */ uint64_t addr; /* in-memory address (subject to alignment) */ uint64_t size; /* in-memory and -file size */ uint64_t offset; /* in-file offset */ @@ -321,10 +322,12 @@ static struct section *get_section_by_name(const char *segname, return s; } -static struct section *get_section_by_index(const int32_t index) +static struct section *get_section_by_index(int32_t index) { struct section *s; + index &= 0x4000fffe; /* Strip subsection but not absolute flag */ + for (s = sects; s != NULL; s = s->next) if (index == s->index) break; @@ -412,6 +415,14 @@ static void macho_init(void) } +static void macho_reset(void) +{ + /* Reset all subsection numbers */ + struct section *s; + for (s = sects; s != NULL; s = s->next) + s->subsection = 0; +} + static void sect_write(struct section *sect, const uint8_t *data, uint32_t len) { @@ -905,6 +916,7 @@ static int32_t macho_section(char *name, int pass, int *bits) s->data = saa_init(1L); s->index = seg_alloc(); + s->subsection = 0; s->fileindex = ++seg_nsects; s->align = -1; s->pad = -1; @@ -987,7 +999,26 @@ static int32_t macho_section(char *name, int pass, int *bits) s->flags |= flags & ~S_NASM_TYPE_MASK; } - return s->index; + return s->index | (s->subsection << 16); +} + +static int32_t macho_herelabel(const char *name, int32_t section) +{ + struct section *s; + + if (!(head_flags & MH_SUBSECTIONS_VIA_SYMBOLS)) + return section; + + /* If it starts with L, it doesn't start a new subsection */ + if (name[0] == 'L') + return section; + + s = get_section_by_index(section); + if (!s) + return section; + + s->subsection++; + return s->index | (s->subsection << 16); } static void macho_symdef(char *name, int32_t section, int64_t offset, @@ -1740,6 +1771,7 @@ static void macho_cleanup(void) } saa_free(strs); + raa_free(extsyms); while (syms) { @@ -2328,10 +2360,12 @@ const struct ofmt of_macho32 = { &macho32_df_dwarf, macho_stdmac, macho32_init, + macho_reset, nasm_do_legacy_output, macho_output, macho_symdef, macho_section, + macho_herelabel, macho_sectalign, macho_segbase, null_directive, @@ -2393,10 +2427,12 @@ const struct ofmt of_macho64 = { &macho64_df_dwarf, macho_stdmac, macho64_init, + macho_reset, nasm_do_legacy_output, macho_output, macho_symdef, macho_section, + macho_herelabel, macho_sectalign, macho_segbase, null_directive, diff --git a/output/outobj.c b/output/outobj.c index bbf90157..5c4da9eb 100644 --- a/output/outobj.c +++ b/output/outobj.c @@ -2707,10 +2707,12 @@ const struct ofmt of_obj = { &borland_debug_form, obj_stdmac, obj_init, + null_reset, nasm_do_legacy_output, obj_out, obj_deflabel, obj_segment, + NULL, obj_sectalign, obj_segbase, obj_directive, diff --git a/output/outrdf2.c b/output/outrdf2.c index 3a218a44..9af827cb 100644 --- a/output/outrdf2.c +++ b/output/outrdf2.c @@ -772,10 +772,12 @@ const struct ofmt of_rdf2 = { &null_debug_form, rdf2_stdmac, rdf2_init, + null_reset, nasm_do_legacy_output, rdf2_out, rdf2_deflabel, rdf2_section_names, + NULL, null_sectalign, rdf2_segbase, rdf2_directive, |