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>
This commit is contained in:
H. Peter Anvin 2018-05-30 14:43:46 -07:00
parent b7136487bd
commit 892c4818ce
18 changed files with 203 additions and 32 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -818,6 +818,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
@ -891,6 +896,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

View File

@ -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);
/*

View File

@ -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 */
}

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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,