diff options
-rw-r--r-- | asm/directiv.c | 5 | ||||
-rw-r--r-- | asm/directiv.dat | 4 | ||||
-rw-r--r-- | asm/eval.c | 8 | ||||
-rw-r--r-- | asm/labels.c | 79 | ||||
-rw-r--r-- | include/labels.h | 13 | ||||
-rw-r--r-- | macros/standard.mac | 7 | ||||
-rw-r--r-- | output/outbin.c | 6 | ||||
-rw-r--r-- | output/outmacho.c | 2 | ||||
-rw-r--r-- | test/elf_visibility.asm | 3 |
9 files changed, 81 insertions, 46 deletions
diff --git a/asm/directiv.c b/asm/directiv.c index 22e6a624..96464d62 100644 --- a/asm/directiv.c +++ b/asm/directiv.c @@ -297,6 +297,9 @@ bool process_directives(char *directive) case D_EXTERN: type = LBL_EXTERN; goto symdef; + case D_REQUIRED: + type = LBL_REQUIRED; + goto symdef; case D_COMMON: type = LBL_COMMON; goto symdef; @@ -356,7 +359,7 @@ bool process_directives(char *directive) if (!declare_label(value, type, special)) break; - if (type == LBL_COMMON || type == LBL_EXTERN) + if (type == LBL_COMMON || type == LBL_EXTERN || type == LBL_REQUIRED) define_label(value, 0, size, false); break; diff --git a/asm/directiv.dat b/asm/directiv.dat index 4b0ca3f0..5659ee14 100644 --- a/asm/directiv.dat +++ b/asm/directiv.dat @@ -44,6 +44,9 @@ ;; same D_ constant will be used for both, and this is perfectly ;; acceptable. ;; +;; In the future, this will be turned into a general list of keywords +;; to be parsed in special contexts. +;; ; --- General configuration #name directive @@ -73,6 +76,7 @@ segment warning sectalign pragma +required ; --- Format-specific directives export ; outcoff, outobj @@ -972,7 +972,9 @@ static expr *expr6(void) label_seg = in_absolute ? absolute.segment : location.segment; label_ofs = in_absolute ? absolute.offset : location.offset; } else { - if (!lookup_label(tokval->t_charptr, &label_seg, &label_ofs)) { + enum label_type ltype; + ltype = lookup_label(tokval->t_charptr, &label_seg, &label_ofs); + if (ltype == LBL_NONE) { scope = local_scope(tokval->t_charptr); if (critical) { nasm_nonfatal("symbol `%s%s' not defined%s", @@ -985,9 +987,9 @@ static expr *expr6(void) type = EXPR_UNKNOWN; label_seg = NO_SEG; label_ofs = 1; - } - if (opflags && is_extern(tokval->t_charptr)) + } else if (is_extern(ltype)) { *opflags |= OPFLAG_EXTERN; + } } addtotemp(type, label_ofs); if (label_seg != NO_SEG) diff --git a/asm/labels.c b/asm/labels.c index f973d7ed..4618fc70 100644 --- a/asm/labels.c +++ b/asm/labels.c @@ -96,9 +96,10 @@ static bool set_prevlabel(const char *l) #endif /* string values for enum label_type */ -static const char * const types[] = -{"local", "global", "static", "extern", "common", "special", - "output format special"}; +static const char * const types[] = { + "local", "static", "global", "extern", "required", "common", + "special", "output format special" +}; union label { /* actual label structures */ struct { @@ -107,6 +108,7 @@ union label { /* actual label structures */ int64_t offset; int64_t size; int64_t defined; /* 0 if undefined, passn+1 for when defn seen */ + int64_t lastref; /* Last pass where we saw a reference */ char *label, *mangled, *special; const char *def_file; /* Where defined */ int32_t def_line; @@ -157,7 +159,7 @@ static void out_symdef(union label *lptr) /* Emit special fixups for globals and commons */ switch (lptr->defn.type) { case LBL_GLOBAL: - case LBL_EXTERN: + case LBL_REQUIRED: case LBL_COMMON: if (lptr->defn.special) ofmt->symdef(lptr->defn.mangled, 0, 0, 3, lptr->defn.special); @@ -173,8 +175,17 @@ static void out_symdef(union label *lptr) /* Clean up this hack... */ switch(lptr->defn.type) { - case LBL_GLOBAL: case LBL_EXTERN: + /* If not seen in the previous or this pass, drop it */ + if (lptr->defn.lastref < pass_count()) + return; + + /* Otherwise, promote to LBL_REQUIRED at this time */ + lptr->defn.type = LBL_REQUIRED; + + /* fall through */ + case LBL_GLOBAL: + case LBL_REQUIRED: backend_type = 1; backend_offset = lptr->defn.offset; break; @@ -255,32 +266,30 @@ static union label *find_label(const char *label, bool create, bool *created) return lfree++; } -bool lookup_label(const char *label, int32_t *segment, int64_t *offset) +enum label_type lookup_label(const char *label, + int32_t *segment, int64_t *offset) { union label *lptr; if (!initialized) - return false; + return LBL_NONE; lptr = find_label(label, false, NULL); if (lptr && lptr->defn.defined) { + int64_t lpass = pass_count() + 1; + + lptr->defn.lastref = lpass; *segment = lptr->defn.segment; *offset = lptr->defn.offset; - return true; + return lptr->defn.type; } - return false; + return LBL_NONE; } -bool is_extern(const char *label) +static inline bool is_global(enum label_type type) { - union label *lptr; - - if (!initialized) - return false; - - lptr = find_label(label, false, NULL); - return lptr && lptr->defn.type == LBL_EXTERN; + return type == LBL_GLOBAL || type == LBL_COMMON; } static const char *mangle_strings[] = {"", "", "", ""}; @@ -314,6 +323,7 @@ static const char *mangle_label_name(union label *lptr) case LBL_GLOBAL: case LBL_STATIC: case LBL_EXTERN: + case LBL_REQUIRED: prefix = mangle_strings[LM_GPREFIX]; suffix = mangle_strings[LM_GSUFFIX]; break; @@ -376,12 +386,15 @@ handle_herelabel(union label *lptr, int32_t *segment, int64_t *offset) static bool declare_label_lptr(union label *lptr, enum label_type type, const char *special) { + enum label_type oldtype = lptr->defn.type; + if (special && !special[0]) special = NULL; - if (lptr->defn.type == type || - (!pass_stable() && lptr->defn.type == LBL_LOCAL)) { + if (oldtype == type || (!pass_stable() && oldtype == LBL_LOCAL) || + (oldtype == LBL_EXTERN && type == LBL_REQUIRED)) { lptr->defn.type = type; + if (special) { if (!lptr->defn.special) lptr->defn.special = perm_copy(special); @@ -390,29 +403,29 @@ static bool declare_label_lptr(union label *lptr, lptr->defn.label, lptr->defn.special, special); } return true; - } - - /* EXTERN can be replaced with GLOBAL or COMMON */ - if (lptr->defn.type == LBL_EXTERN && - (type == LBL_GLOBAL || type == LBL_COMMON)) { + } else if (is_extern(oldtype) && is_global(type)) { + /* EXTERN or REQUIRED can be replaced with GLOBAL or COMMON */ lptr->defn.type = type; + /* Override special unconditionally */ if (special) lptr->defn.special = perm_copy(special); return true; - } + } else if (is_extern(type) && (is_global(oldtype) || is_extern(oldtype))) { + /* + * GLOBAL or COMMON ignore subsequent EXTERN or REQUIRED; + * REQUIRED ignores subsequent EXTERN. + */ - /* GLOBAL or COMMON ignore subsequent EXTERN */ - if ((lptr->defn.type == LBL_GLOBAL || lptr->defn.type == LBL_COMMON) && - type == LBL_EXTERN) { + /* Ignore special unless we don't already have one */ if (!lptr->defn.special) lptr->defn.special = perm_copy(special); - return false; /* Don't call define_label() after this! */ + + return false; /* Don't call define_label() after this! */ } nasm_nonfatal("symbol `%s' declared both as %s and %s", lptr->defn.label, types[lptr->defn.type], types[type]); - return false; } @@ -452,13 +465,13 @@ void define_label(const char *label, int32_t segment, if (segment) { /* We are actually defining this label */ - if (lptr->defn.type == LBL_EXTERN) { - /* auto-promote EXTERN to GLOBAL */ + if (is_extern(lptr->defn.type)) { + /* auto-promote EXTERN/REQUIRED to GLOBAL */ lptr->defn.type = LBL_GLOBAL; lastdef = 0; /* We are "re-creating" this label */ } } else { - /* It's a pseudo-segment (extern, common) */ + /* It's a pseudo-segment (extern, required, common) */ segment = lptr->defn.segment ? lptr->defn.segment : seg_alloc(); } diff --git a/include/labels.h b/include/labels.h index 9cf57c1b..32df8071 100644 --- a/include/labels.h +++ b/include/labels.h @@ -48,17 +48,22 @@ enum mangle_index { }; enum label_type { - LBL_LOCAL, /* Must be zero */ - LBL_GLOBAL, + LBL_NONE = -1, /* No label */ + LBL_LOCAL = 0, /* Must be zero */ LBL_STATIC, + LBL_GLOBAL, LBL_EXTERN, + LBL_REQUIRED, /* Like extern but emit even if unused */ LBL_COMMON, LBL_SPECIAL, /* Magic symbols like ..start */ LBL_BACKEND /* Backend-defined symbols like ..got */ }; -bool lookup_label(const char *label, int32_t *segment, int64_t *offset); -bool is_extern(const char *label); +enum label_type lookup_label(const char *label, int32_t *segment, int64_t *offset); +static inline bool is_extern(enum label_type type) +{ + return type == LBL_EXTERN || type == LBL_REQUIRED; +} void define_label(const char *label, int32_t segment, int64_t offset, bool normal); void backend_label(const char *label, int32_t segment, int64_t offset); diff --git a/macros/standard.mac b/macros/standard.mac index f6ca65d2..a2ab4fc1 100644 --- a/macros/standard.mac +++ b/macros/standard.mac @@ -166,6 +166,13 @@ STD: nasm %endrep %endmacro +%imacro required 1-*.nolist + %rep %0 + [required %1] + %rotate 1 + %endrep +%endmacro + %imacro common 1-*.nolist %rep %0 [common %1] diff --git a/output/outbin.c b/output/outbin.c index 8baa648a..5c2f0631 100644 --- a/output/outbin.c +++ b/output/outbin.c @@ -642,7 +642,7 @@ static void bin_cleanup(void) if (map_control & MAP_SYMBOLS) { int32_t segment; int64_t offset; - bool found_label; + enum label_type found_label; fprintf(rf, "-- Symbols "); for (h = 68; h; h--) @@ -655,7 +655,7 @@ static void bin_cleanup(void) fprintf(rf, "\n\nValue Name\n"); list_for_each(l, no_seg_labels) { found_label = lookup_label(l->name, &segment, &offset); - nasm_assert(found_label); + nasm_assert(found_label != LBL_NONE); fprintf(rf, "%08"PRIX64" %s\n", offset, l->name); } fprintf(rf, "\n\n"); @@ -668,7 +668,7 @@ static void bin_cleanup(void) fprintf(rf, "\n\nReal Virtual Name\n"); list_for_each(l, s->labels) { found_label = lookup_label(l->name, &segment, &offset); - nasm_assert(found_label); + nasm_assert(found_label != LBL_NONE); fprintf(rf, "%16"PRIX64" %16"PRIX64" %s\n", s->start + offset, s->vstart + offset, l->name); diff --git a/output/outmacho.c b/output/outmacho.c index 5ad6601d..6cbaa012 100644 --- a/output/outmacho.c +++ b/output/outmacho.c @@ -1740,7 +1740,7 @@ static bool macho_set_section_attribute_by_symbol(const char *label, uint32_t fl int32_t nasm_seg; int64_t offset; - if (!lookup_label(label, &nasm_seg, &offset)) { + if (lookup_label(label, &nasm_seg, &offset) == LBL_NONE) { nasm_error(ERR_NONFATAL, "unknown symbol `%s' in no_dead_strip", label); return false; } diff --git a/test/elf_visibility.asm b/test/elf_visibility.asm index 8098e227..81ea7a0c 100644 --- a/test/elf_visibility.asm +++ b/test/elf_visibility.asm @@ -5,7 +5,8 @@ global foo_internal:function internal global foo_weak:function weak global foo_hidden_weak:function hidden weak -extern strong_ref, weak_ref:weak +extern strong_ref, weak_ref:weak, unused_ref +required required_ref SECTION .text align=16 |