summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--asm/directiv.c5
-rw-r--r--asm/directiv.dat4
-rw-r--r--asm/eval.c8
-rw-r--r--asm/labels.c79
-rw-r--r--include/labels.h13
-rw-r--r--macros/standard.mac7
-rw-r--r--output/outbin.c6
-rw-r--r--output/outmacho.c2
-rw-r--r--test/elf_visibility.asm3
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
diff --git a/asm/eval.c b/asm/eval.c
index 9ec093a0..db915ef2 100644
--- a/asm/eval.c
+++ b/asm/eval.c
@@ -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