Cleanup of label renaming infrastructure, add subsection support

In order to support Mach-O better, add support for subsections, as
used by Mach-O "subsections_via_symbols". We also want to add
infrastructure to support this by downcalling to the backend to
indicate if a new subsection is needed.

Currently this supports a maximum of 2^14 subsections per section for
Mach-O; this can be addressed by adding a level of indirection (or
cleaning up the handling of sections so we have an actual data
structure.)

Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
This commit is contained in:
H. Peter Anvin 2018-06-01 18:02:54 -07:00
parent 8413e8167a
commit 98578071b9
21 changed files with 508 additions and 530 deletions

View file

@ -209,6 +209,7 @@ bool process_directives(char *directive)
struct tokenval tokval;
bool bad_param = false;
int pass2 = passn > 1 ? 2 : 1;
enum label_type type;
d = parse_directive_line(&directive, &value);
@ -292,140 +293,80 @@ bool process_directives(char *directive)
break;
}
case D_EXTERN: /* [EXTERN label:special] */
if (*value == '$')
value++; /* skip initial $ if present */
if (pass0 == 2) {
q = value;
while (*q && *q != ':')
q++;
if (*q == ':') {
*q++ = '\0';
ofmt->symdef(value, 0L, 0L, 3, q);
}
} else if (passn == 1) {
bool validid = true;
q = value;
if (!isidstart(*q))
validid = false;
while (*q && *q != ':') {
if (!isidchar(*q))
validid = false;
q++;
}
if (!validid) {
nasm_error(ERR_NONFATAL, "identifier expected after EXTERN");
break;
}
if (*q == ':') {
*q++ = '\0';
special = q;
} else
special = NULL;
if (!is_extern(value)) { /* allow re-EXTERN to be ignored */
int temp = pass0;
pass0 = 1; /* fake pass 1 in labels.c */
declare_as_global(value, special);
define_label(value, seg_alloc(), 0L, NULL,
false, true);
pass0 = temp;
}
} /* else pass0 == 1 */
break;
case D_BITS: /* [BITS bits] */
globalbits = get_bits(value);
break;
case D_GLOBAL: /* [GLOBAL symbol:special] */
if (*value == '$')
value++; /* skip initial $ if present */
if (pass0 == 2) { /* pass 2 */
q = value;
while (*q && *q != ':')
q++;
if (*q == ':') {
*q++ = '\0';
ofmt->symdef(value, 0L, 0L, 3, q);
}
} else if (pass2 == 1) { /* pass == 1 */
bool validid = true;
case D_GLOBAL: /* [GLOBAL|STATIC|EXTERN|COMMON symbol:special] */
type = LBL_GLOBAL;
goto symdef;
case D_STATIC:
type = LBL_STATIC;
goto symdef;
case D_EXTERN:
type = LBL_EXTERN;
goto symdef;
case D_COMMON:
type = LBL_COMMON;
goto symdef;
q = value;
if (!isidstart(*q))
validid = false;
while (*q && *q != ':') {
if (!isidchar(*q))
validid = false;
q++;
}
if (!validid) {
nasm_error(ERR_NONFATAL,
"identifier expected after GLOBAL");
break;
}
if (*q == ':') {
*q++ = '\0';
special = q;
} else
special = NULL;
declare_as_global(value, special);
} /* pass == 1 */
break;
case D_COMMON: /* [COMMON symbol size:special] */
symdef:
{
int64_t size;
bool rn_error;
bool validid;
bool validid = true;
int64_t size = 0;
char *sizestr;
bool rn_error;
if (*value == '$')
value++; /* skip initial $ if present */
p = value;
validid = true;
if (!isidstart(*p))
q = value;
if (!isidstart(*q))
validid = false;
while (*p && !nasm_isspace(*p)) {
if (!isidchar(*p))
while (*q && *q != ':' && !nasm_isspace(*q)) {
if (!isidchar(*q))
validid = false;
p++;
q++;
}
if (!validid) {
nasm_error(ERR_NONFATAL, "identifier expected after COMMON");
break;
}
if (*p) {
p = nasm_zap_spaces_fwd(p);
q = p;
while (*q && *q != ':')
q++;
if (*q == ':') {
*q++ = '\0';
special = q;
} else {
special = NULL;
}
size = readnum(p, &rn_error);
if (rn_error) {
nasm_error(ERR_NONFATAL,
"invalid size specified"
" in COMMON declaration");
break;
}
} else {
nasm_error(ERR_NONFATAL,
"no size specified in"
" COMMON declaration");
"identifier expected after %s", directive);
break;
}
if (pass0 < 2) {
define_common(value, seg_alloc(), size, special);
} else if (pass0 == 2) {
if (special)
ofmt->symdef(value, 0L, 0L, 3, special);
if (nasm_isspace(*q)) {
sizestr = q = nasm_zap_spaces_fwd(q);
q = strchr(q, ':');
} else {
sizestr = NULL;
}
break;
if (*q == ':') {
*q++ = '\0';
special = q;
} else {
special = NULL;
}
if (type == LBL_COMMON) {
if (sizestr)
size = readnum(sizestr, &rn_error);
if (!sizestr || rn_error)
nasm_error(ERR_NONFATAL,
"%s size specified in common declaration",
sizestr ? "invalid" : "no");
} else if (sizestr) {
nasm_error(ERR_NONFATAL, "invalid syntax in %s declaration",
directive);
}
if (*value == '$')
value++; /* skip initial $ if present */
if (!declare_label(value, type, special))
break;
if (type == LBL_COMMON || type == LBL_EXTERN)
define_label(value, 0, size, false);
break;
}
case D_ABSOLUTE: /* [ABSOLUTE address] */

View file

@ -66,6 +66,7 @@ default
extern
float
global
static
list
section
segment
@ -85,6 +86,14 @@ osabi ; outelf
safeseh ; outcoff
uppercase ; outieee, outobj
; --- Assembler pragmas
prefix
suffix
gprefix
gsuffix
lprefix
lsuffix
; --- Pragma operations
subsections_via_symbols ; macho
no_dead_strip ; macho

View file

@ -767,7 +767,7 @@ static expr *expr6(int critical)
int64_t label_ofs;
int64_t tmpval;
bool rn_warn;
char *scope;
const char *scope;
switch (i) {
case '-':

View file

@ -48,21 +48,29 @@
#include "labels.h"
/*
* A local label is one that begins with exactly one period. Things
* A dot-local label is one that begins with exactly one period. Things
* that begin with _two_ periods are NASM-specific things.
*
* If TASM compatibility is enabled, a local label can also begin with
* @@, so @@local is a TASM compatible local label. Note that we only
* check for the first @ symbol, although TASM requires both.
* @@.
*/
#define islocal(l) \
(tasm_compatible_mode ? \
(((l)[0] == '.' || (l)[0] == '@') && (l)[1] != '.') : \
((l)[0] == '.' && (l)[1] != '.'))
#define islocalchar(c) \
(tasm_compatible_mode ? \
((c) == '.' || (c) == '@') : \
((c) == '.'))
static bool islocal(const char *l)
{
if (tasm_compatible_mode) {
if (l[0] == '@' && l[1] == '@')
return true;
}
return (l[0] == '.' && l[1] != '.');
}
/*
* Return true if this falls into NASM's '..' namespace
*/
static bool ismagic(const char *l)
{
return l[0] == '.' && l[1] == '.' && l[2] != '@';
}
#define LABEL_BLOCK 128 /* no. of labels/block */
#define LBLK_SIZE (LABEL_BLOCK * sizeof(union label))
@ -76,24 +84,18 @@
#error "IPERMTS_SIZE must be greater than or equal to IDLEN_MAX"
#endif
/* values for label.defn.is_global */
#define DEFINED_BIT 1
#define GLOBAL_BIT 2
#define EXTERN_BIT 4
#define COMMON_BIT 8
#define NOT_DEFINED_YET 0
#define TYPE_MASK 3
#define LOCAL_SYMBOL (DEFINED_BIT)
#define GLOBAL_PLACEHOLDER (GLOBAL_BIT)
#define GLOBAL_SYMBOL (DEFINED_BIT | GLOBAL_BIT)
/* string values for enum label_type */
static const char * const types[] =
{"local", "global", "static", "extern", "common", "special",
"output format special"};
union label { /* actual label structures */
struct {
int32_t segment;
int64_t offset;
char *label, *special;
int is_global, is_norm;
char *label, *mangled, *special;
enum label_type type, mangled_type;
bool defined;
} defn;
struct {
int32_t movingon;
@ -104,9 +106,10 @@ union label { /* actual label structures */
struct permts { /* permanent text storage */
struct permts *next; /* for the linked list */
int size, usage; /* size and used space in ... */
unsigned int size, usage; /* size and used space in ... */
char data[PERMTS_SIZE]; /* ... the data block itself */
};
#define PERMTS_HEADER offsetof(struct permts, data)
uint64_t global_offset_changed; /* counter for global offset changes */
@ -117,29 +120,71 @@ static struct permts *perm_head; /* start of perm. text storage */
static struct permts *perm_tail; /* end of perm. text storage */
static void init_block(union label *blk);
static char *perm_alloc(size_t len);
static char *perm_copy(const char *string);
static char *perm_copy3(const char *s1, const char *s2, const char *s3);
static const char *mangle_label_name(union label *lptr);
static char *prevlabel;
static const char *prevlabel;
static bool initialized = false;
char lprefix[PREFIX_MAX] = { 0 };
char lpostfix[PREFIX_MAX] = { 0 };
/*
* Emit a symdef to the output and the debug format backends.
*/
static void out_symdef(char *name, int32_t segment, int64_t offset,
int is_global, char *special)
static void out_symdef(union label *lptr)
{
ofmt->symdef(name, segment, offset, is_global, special);
int backend_type;
/* Backend-defined special segments are passed to symdef immediately */
if (pass0 == 2) {
/* Emit special fixups for globals and commons */
switch (lptr->defn.type) {
case LBL_GLOBAL:
case LBL_COMMON:
case LBL_EXTERN:
if (lptr->defn.special)
ofmt->symdef(lptr->defn.label, 0, 0, 3, lptr->defn.special);
break;
default:
break;
}
return;
}
if (pass0 != 1 && lptr->defn.type != LBL_BACKEND)
return;
/* Clean up this hack... */
switch(lptr->defn.type) {
case LBL_GLOBAL:
backend_type = 1;
break;
case LBL_COMMON:
backend_type = 2;
break;
default:
backend_type = 0;
break;
}
/* Might be necessary for a backend symbol */
mangle_label_name(lptr);
ofmt->symdef(lptr->defn.mangled, lptr->defn.segment,
lptr->defn.offset, backend_type,
lptr->defn.special);
/*
* NASM special symbols are not passed to the debug format; none
* of the current backends want to see them.
*/
if (!(name[0] == '.' && name[1] == '.' && name[2] != '@'))
dfmt->debug_deflabel(name, segment, offset, is_global, special);
if (lptr->defn.type == LBL_SPECIAL || lptr->defn.type == LBL_BACKEND)
return;
dfmt->debug_deflabel(lptr->defn.mangled, lptr->defn.segment,
lptr->defn.offset, backend_type,
lptr->defn.special);
}
/*
@ -147,37 +192,21 @@ static void out_symdef(char *name, int32_t segment, int64_t offset,
* given label name. Creates a new one, if it isn't found, and if
* `create' is true.
*/
static union label *find_label(const char *label, int create, int *created)
static union label *find_label(const char *label, bool create, bool *created)
{
char *prev;
int prevlen, len;
union label *lptr, **lpp;
char label_str[IDLEN_MAX];
char *label_str = NULL;
struct hash_insert ip;
if (islocal(label)) {
prev = prevlabel;
prevlen = strlen(prev);
len = strlen(label);
if (prevlen + len >= IDLEN_MAX) {
nasm_error(ERR_NONFATAL, "identifier length exceed %i bytes",
IDLEN_MAX);
return NULL;
}
memcpy(label_str, prev, prevlen);
memcpy(label_str+prevlen, label, len+1);
label = label_str;
} else {
prev = "";
prevlen = 0;
}
if (islocal(label))
label = label_str = nasm_strcat(prevlabel, label);
lpp = (union label **) hash_find(&ltab, label, &ip);
lptr = lpp ? *lpp : NULL;
if (lptr || !create) {
if (created)
*created = 0;
*created = false;
return lptr;
}
@ -192,12 +221,13 @@ static union label *find_label(const char *label, int create, int *created)
}
if (created)
*created = 1;
*created = true;
nasm_zero(*lfree);
lfree->admin.movingon = BOGUS_VALUE;
lfree->defn.label = perm_copy(label);
lfree->defn.special = NULL;
lfree->defn.is_global = NOT_DEFINED_YET;
lfree->defn.label = perm_copy(label);
if (label_str)
nasm_free(label_str);
hash_add(&ip, lfree->defn.label, lfree);
return lfree++;
@ -210,8 +240,8 @@ bool lookup_label(const char *label, int32_t *segment, int64_t *offset)
if (!initialized)
return false;
lptr = find_label(label, 0, NULL);
if (lptr && (lptr->defn.is_global & DEFINED_BIT)) {
lptr = find_label(label, false, NULL);
if (lptr && lptr->defn.defined) {
*segment = lptr->defn.segment;
*offset = lptr->defn.offset;
return true;
@ -227,12 +257,66 @@ bool is_extern(const char *label)
if (!initialized)
return false;
lptr = find_label(label, 0, NULL);
return (lptr && (lptr->defn.is_global & EXTERN_BIT));
lptr = find_label(label, false, NULL);
return lptr && lptr->defn.type == LBL_EXTERN;
}
static void handle_herelabel(const char *label,
int32_t *segment, int64_t *offset)
static const char *mangle_strings[] = {"", "", "", ""};
static bool mangle_string_set[ARRAY_SIZE(mangle_strings)];
/*
* Set a prefix or suffix
*/
void set_label_mangle(enum mangle_index which, const char *what)
{
if (mangle_string_set[which])
return; /* Once set, do not change */
mangle_strings[which] = perm_copy(what);
mangle_string_set[which] = true;
}
/*
* Format a label name with appropriate prefixes and suffixes
*/
static const char *mangle_label_name(union label *lptr)
{
const char *prefix;
const char *suffix;
if (likely(lptr->defn.mangled &&
lptr->defn.mangled_type == lptr->defn.type))
return lptr->defn.mangled; /* Already mangled */
switch (lptr->defn.type) {
case LBL_GLOBAL:
case LBL_STATIC:
case LBL_EXTERN:
prefix = mangle_strings[LM_GPREFIX];
suffix = mangle_strings[LM_GSUFFIX];
break;
case LBL_BACKEND:
case LBL_SPECIAL:
prefix = suffix = "";
break;
default:
prefix = mangle_strings[LM_LPREFIX];
suffix = mangle_strings[LM_LSUFFIX];
break;
}
lptr->defn.mangled_type = lptr->defn.type;
if (!(*prefix) && !(*suffix))
lptr->defn.mangled = lptr->defn.label;
else
lptr->defn.mangled = perm_copy3(prefix, lptr->defn.label, suffix);
return lptr->defn.mangled;
}
static void
handle_herelabel(const union label *lptr, int32_t *segment, int64_t *offset)
{
int32_t oldseg;
@ -248,7 +332,8 @@ static void handle_herelabel(const char *label,
/* This label is defined at this location */
int32_t newseg;
newseg = ofmt->herelabel(label, oldseg);
nasm_assert(lptr->defn.mangled);
newseg = ofmt->herelabel(lptr->defn.mangled, lptr->defn.type, oldseg);
if (likely(newseg == oldseg))
return;
@ -257,198 +342,120 @@ static void handle_herelabel(const char *label,
}
}
void redefine_label(char *label, int32_t segment, int64_t offset, char *special,
bool is_norm, bool isextrn)
static bool declare_label_lptr(union label *lptr,
enum label_type type, const char *special)
{
if (lptr->defn.type == type ||
(pass0 == 0 && lptr->defn.type == LBL_LOCAL)) {
lptr->defn.type = type;
if (special) {
if (!lptr->defn.special)
lptr->defn.special = perm_copy(special);
else if (nasm_stricmp(lptr->defn.special, special))
nasm_error(ERR_NONFATAL,
"symbol `%s' has inconsistent attributes `%s' and `%s'",
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)) {
lptr->defn.type = type;
/* Override special unconditionally */
if (special)
lptr->defn.special = perm_copy(special);
return true;
}
/* GLOBAL or COMMON ignore subsequent EXTERN */
if ((lptr->defn.type == LBL_GLOBAL || lptr->defn.type == LBL_COMMON) &&
type == LBL_EXTERN) {
if (!lptr->defn.special)
lptr->defn.special = perm_copy(special);
return true;
}
nasm_error(ERR_NONFATAL, "symbol `%s' declared both as %s and %s",
lptr->defn.label, types[lptr->defn.type], types[type]);
return false;
}
bool declare_label(const char *label, enum label_type type, const char *special)
{
union label *lptr;
int exi, created;
bool created;
/* This routine possibly ought to check for phase errors. Most assemblers
* check for phase errors at this point. I don't know whether phase errors
* are even possible, nor whether they are checked somewhere else
lptr = find_label(label, true, &created);
return declare_label_lptr(lptr, type, special);
}
/*
* The "normal" argument decides if we should update the local segment
* base name or not.
*/
void define_label(const char *label, int32_t segment,
int64_t offset, bool normal)
{
union label *lptr;
bool created, changed;
/*
* Phase errors here can be one of two types: a new label appears,
* or the offset changes. Increment global_offset_changed when that
* happens, to tell the assembler core to make another pass.
*/
lptr = find_label(label, true, &created);
(void)special; /* Don't warn that this parameter is unused */
(void)is_norm; /* Don't warn that this parameter is unused */
(void)isextrn; /* Don't warn that this parameter is unused */
#ifdef DEBUG
#if DEBUG < 3
if (!strncmp(label, "debugdump", 9))
#endif
nasm_error(ERR_DEBUG, "redefine_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, &created);
if (!lptr)
nasm_panic(0, "can't find label `%s' on pass two", label);
if (created)
if (pass0 > 1) {
if (created)
nasm_error(ERR_WARNING, "label `%s' defined on pass two", label);
if (!islocal(label)) {
if (!islocalchar(*label) && lptr->defn.is_norm)
prevlabel = lptr->defn.label;
}
if (lptr->defn.offset != offset)
global_offset_changed++;
lptr->defn.offset = offset;
lptr->defn.segment = segment;
if (pass0 == 1) {
exi = !!(lptr->defn.is_global & GLOBAL_BIT);
if (exi) {
char *xsymbol;
int slen;
slen = strlen(lprefix);
slen += strlen(lptr->defn.label);
slen += strlen(lpostfix);
slen++; /* room for that null char */
xsymbol = nasm_malloc(slen);
snprintf(xsymbol, slen, "%s%s%s", lprefix, lptr->defn.label,
lpostfix);
out_symdef(xsymbol, segment, offset, exi,
special ? special : lptr->defn.special);
/** nasm_free(xsymbol); ! outobj.c stores the pointer; ouch!!! **/
} else {
if ((lptr->defn.is_global & (GLOBAL_BIT | EXTERN_BIT)) != EXTERN_BIT) {
out_symdef(lptr->defn.label, segment, offset, exi,
special ? special : lptr->defn.special);
}
}
} /* if (pass0 == 1) */
}
void define_label(char *label, int32_t segment, int64_t offset, char *special,
bool is_norm, bool isextrn)
{
union label *lptr;
int exi;
#ifdef DEBUG
#if DEBUG<3
if (!strncmp(label, "debugdump", 9))
#endif
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;
if (lptr->defn.is_global & DEFINED_BIT) {
nasm_error(ERR_NONFATAL, "symbol `%s' redefined", label);
return;
if (lptr->defn.defined || lptr->defn.type == LBL_BACKEND) {
/* We have seen this on at least one previous pass */
mangle_label_name(lptr);
handle_herelabel(lptr, &segment, &offset);
}
lptr->defn.is_global |= DEFINED_BIT;
if (isextrn)
lptr->defn.is_global |= EXTERN_BIT;
if (!islocalchar(label[0]) && is_norm) {
/* not local, but not special either */
if (ismagic(label) && lptr->defn.type == LBL_LOCAL)
lptr->defn.type = LBL_SPECIAL;
if (!islocal(label) && normal) {
prevlabel = lptr->defn.label;
} else if (islocal(label) && !*prevlabel) {
nasm_error(ERR_NONFATAL, "attempt to define a local label before any"
" non-local labels");
}
changed = !lptr->defn.defined || lptr->defn.segment != segment ||
lptr->defn.offset != offset;
global_offset_changed += changed;
/*
* This probably should be ERR_NONFATAL, but not quite yet. As a
* special case, LBL_SPECIAL symbols are allowed to be changed
* even during the last pass.
*/
if (changed && pass0 == 2 && lptr->defn.type != LBL_SPECIAL)
nasm_error(ERR_WARNING, "label `%s' changed during code generation",
lptr->defn.label);
lptr->defn.segment = segment;
lptr->defn.offset = offset;
lptr->defn.is_norm = (!islocalchar(label[0]) && is_norm);
lptr->defn.offset = offset;
lptr->defn.defined = true;
if (pass0 == 1 || (!is_norm && !isextrn && (segment > 0) && (segment & 1))) {
exi = !!(lptr->defn.is_global & GLOBAL_BIT);
if (exi) {
char *xsymbol;
int slen;
slen = strlen(lprefix);
slen += strlen(lptr->defn.label);
slen += strlen(lpostfix);
slen++; /* room for that null char */
xsymbol = nasm_malloc(slen);
snprintf(xsymbol, slen, "%s%s%s", lprefix, lptr->defn.label,
lpostfix);
out_symdef(xsymbol, segment, offset, exi,
special ? special : lptr->defn.special);
/** nasm_free(xsymbol); ! outobj.c stores the pointer; ouch!!! **/
} else {
if ((lptr->defn.is_global & (GLOBAL_BIT | EXTERN_BIT)) != EXTERN_BIT) {
out_symdef(lptr->defn.label, segment, offset, exi,
special ? special : lptr->defn.special);
}
}
} /* if (pass0 == 1) */
out_symdef(lptr);
}
void define_common(char *label, int32_t segment, int32_t size, char *special)
/*
* Define a special backend label
*/
void backend_label(const char *label, int32_t segment, int64_t offset)
{
union label *lptr;
lptr = find_label(label, 1, NULL);
if (!lptr)
return;
if ((lptr->defn.is_global & DEFINED_BIT) &&
(passn == 1 || !(lptr->defn.is_global & COMMON_BIT))) {
nasm_error(ERR_NONFATAL, "symbol `%s' redefined", label);
return;
}
lptr->defn.is_global |= DEFINED_BIT|COMMON_BIT;
if (!islocalchar(label[0])) {
prevlabel = lptr->defn.label;
} else {
nasm_error(ERR_NONFATAL, "attempt to define a local label as a "
"common variable");
return;
}
lptr->defn.segment = segment;
lptr->defn.offset = 0;
if (pass0 == 0)
if (!declare_label(label, LBL_BACKEND, NULL))
return;
out_symdef(lptr->defn.label, segment, size, 2,
special ? special : lptr->defn.special);
}
void declare_as_global(char *label, char *special)
{
union label *lptr;
if (islocal(label)) {
nasm_error(ERR_NONFATAL, "attempt to declare local symbol `%s' as"
" global", label);
return;
}
lptr = find_label(label, 1, NULL);
if (!lptr)
return;
switch (lptr->defn.is_global & TYPE_MASK) {
case NOT_DEFINED_YET:
lptr->defn.is_global = GLOBAL_PLACEHOLDER;
lptr->defn.special = special ? perm_copy(special) : NULL;
break;
case GLOBAL_PLACEHOLDER: /* already done: silently ignore */
case GLOBAL_SYMBOL:
break;
case LOCAL_SYMBOL:
if (!(lptr->defn.is_global & EXTERN_BIT)) {
nasm_error(ERR_WARNING, "symbol `%s': GLOBAL directive "
"after symbol definition is an experimental feature", label);
lptr->defn.is_global = GLOBAL_SYMBOL;
}
break;
}
define_label(label, segment, offset, false);
}
int init_labels(void)
@ -505,29 +512,53 @@ static void init_block(union label *blk)
blk[LABEL_BLOCK - 1].admin.next = NULL;
}
static char * safe_alloc perm_alloc(size_t len)
{
if (perm_tail->size - perm_tail->usage < len) {
size_t alloc_len = (len > PERMTS_SIZE) ? len : PERMTS_SIZE;
perm_tail->next = nasm_malloc(PERMTS_HEADER + alloc_len);
perm_tail = perm_tail->next;
perm_tail->next = NULL;
perm_tail->size = alloc_len;
perm_tail->usage = 0;
}
perm_tail->usage += len;
return perm_tail->data + perm_tail->usage;
}
static char *perm_copy(const char *string)
{
char *p;
int len = strlen(string)+1;
size_t len;
nasm_assert(len <= PERMTS_SIZE);
if (!string)
return NULL;
if (perm_tail->size - perm_tail->usage < len) {
perm_tail->next =
nasm_malloc(sizeof(struct permts));
perm_tail = perm_tail->next;
perm_tail->next = NULL;
perm_tail->size = PERMTS_SIZE;
perm_tail->usage = 0;
}
p = perm_tail->data + perm_tail->usage;
len = strlen(string)+1; /* Include final NUL */
p = perm_alloc(len);
memcpy(p, string, len);
perm_tail->usage += len;
return p;
}
char *local_scope(char *label)
static char * safe_alloc
perm_copy3(const char *s1, const char *s2, const char *s3)
{
char *p;
size_t l1 = strlen(s1);
size_t l2 = strlen(s2);
size_t l3 = strlen(s3)+1; /* Include final NUL */
p = perm_alloc(l1+l2+l3);
memcpy(p, s1, l1);
memcpy(p+l1, s2, l2);
memcpy(p+l1+l2, s3, l3);
return p;
}
const char *local_scope(const char *label)
{
return islocal(label) ? prevlabel : "";
}

View file

@ -718,21 +718,25 @@ enum text_options {
OPT_BOGUS,
OPT_VERSION,
OPT_ABORT_ON_PANIC,
OPT_PREFIX,
OPT_POSTFIX
OPT_MANGLE
};
struct textargs {
const char *label;
enum text_options opt;
bool need_arg;
int pvt;
};
static const struct textargs textopts[] = {
{"v", OPT_VERSION, false},
{"version", OPT_VERSION, false},
{"abort-on-panic", OPT_ABORT_ON_PANIC, false},
{"prefix", OPT_PREFIX, true},
{"postfix", OPT_POSTFIX, true},
{NULL, OPT_BOGUS, false}
{"v", OPT_VERSION, false, 0},
{"version", OPT_VERSION, false, 0},
{"abort-on-panic", OPT_ABORT_ON_PANIC, false, 0},
{"prefix", OPT_MANGLE, true, LM_GPREFIX},
{"postfix", OPT_MANGLE, true, LM_GSUFFIX},
{"gprefix", OPT_MANGLE, true, LM_GPREFIX},
{"gpostfix", OPT_MANGLE, true, LM_GSUFFIX},
{"lprefix", OPT_MANGLE, true, LM_LPREFIX},
{"lpostfix", OPT_MANGLE, true, LM_LSUFFIX},
{NULL, OPT_BOGUS, false, 0}
};
static void show_version(void)
@ -930,7 +934,10 @@ static bool process_arg(char *p, char *q, int pass)
" -h show invocation summary and exit\n\n"
"--prefix,--postfix\n"
" these options prepend or append the given string\n"
" to all extern and global variables\n"
" to all extern, common and global symbols\n"
"--lprefix,--lportfix\n"
" these options prepend or append the given string\n"
" to all other symbols\n"
"\n"
"Response files should contain command line parameters,\n"
"one per line.\n"
@ -1081,13 +1088,9 @@ static bool process_arg(char *p, char *q, int pass)
case OPT_ABORT_ON_PANIC:
abort_on_panic = true;
break;
case OPT_PREFIX:
case OPT_MANGLE:
if (pass == 2)
strlcpy(lprefix, q, PREFIX_MAX);
break;
case OPT_POSTFIX:
if (pass == 2)
strlcpy(lpostfix, q, POSTFIX_MAX);
set_label_mangle(tx->pvt, q);
break;
case OPT_BOGUS:
nasm_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
@ -1324,14 +1327,10 @@ static void assemble_file(const char *fname, StrList **depend_ptr)
pass_max = prev_offset_changed = (INT_MAX >> 1) + 2; /* Almost unlimited */
for (passn = 1; pass0 <= 2; passn++) {
ldfunc def_label;
pass1 = pass0 == 2 ? 2 : 1; /* 1, 1, 1, ..., 1, 2 */
pass2 = passn > 1 ? 2 : 1; /* 1, 2, 2, ..., 2, 2 */
/* pass0 0, 0, 0, ..., 1, 2 */
def_label = passn > 1 ? redefine_label : define_label;
globalbits = cmd_sb; /* set 'bits' to command line default */
cpu = cmd_cpu;
if (pass0 == 2) {
@ -1376,8 +1375,7 @@ static void assemble_file(const char *fname, StrList **depend_ptr)
goto end_of_line; /* Just do final cleanup */
/* Not a directive, or even something that starts with [ */
parse_line(pass1, line, &output_ins, def_label);
parse_line(pass1, line, &output_ins);
if (optimizing > 0) {
if (forwref != NULL && globallineno == forwref->lineno) {
@ -1405,71 +1403,29 @@ static void assemble_file(const char *fname, StrList **depend_ptr)
/* forw_ref */
if (output_ins.opcode == I_EQU) {
if (pass1 == 1) {
/*
* Special `..' EQUs get processed in pass two,
* except `..@' macro-processor EQUs which are done
* in the normal place.
*/
if (!output_ins.label)
nasm_error(ERR_NONFATAL,
"EQU not preceded by label");
else if (output_ins.label[0] != '.' ||
output_ins.label[1] != '.' ||
output_ins.label[2] == '@') {
if (output_ins.operands == 1 &&
(output_ins.oprs[0].type & IMMEDIATE) &&
output_ins.oprs[0].wrt == NO_SEG) {
bool isext = !!(output_ins.oprs[0].opflags & OPFLAG_EXTERN);
def_label(output_ins.label,
output_ins.oprs[0].segment,
output_ins.oprs[0].offset, NULL,
false, isext);
} else if (output_ins.operands == 2
&& (output_ins.oprs[0].type & IMMEDIATE)
&& (output_ins.oprs[0].type & COLON)
&& output_ins.oprs[0].segment == NO_SEG
&& output_ins.oprs[0].wrt == NO_SEG
&& (output_ins.oprs[1].type & IMMEDIATE)
&& output_ins.oprs[1].segment == NO_SEG
&& output_ins.oprs[1].wrt == NO_SEG) {
def_label(output_ins.label,
output_ins.oprs[0].offset | SEG_ABS,
output_ins.oprs[1].offset,
NULL, false, false);
} else
nasm_error(ERR_NONFATAL,
"bad syntax for EQU");
}
if (!output_ins.label)
nasm_error(ERR_NONFATAL,
"EQU not preceded by label");
if (output_ins.operands == 1 &&
(output_ins.oprs[0].type & IMMEDIATE) &&
output_ins.oprs[0].wrt == NO_SEG) {
define_label(output_ins.label,
output_ins.oprs[0].segment,
output_ins.oprs[0].offset, false);
} else if (output_ins.operands == 2
&& (output_ins.oprs[0].type & IMMEDIATE)
&& (output_ins.oprs[0].type & COLON)
&& output_ins.oprs[0].segment == NO_SEG
&& output_ins.oprs[0].wrt == NO_SEG
&& (output_ins.oprs[1].type & IMMEDIATE)
&& output_ins.oprs[1].segment == NO_SEG
&& output_ins.oprs[1].wrt == NO_SEG) {
define_label(output_ins.label,
output_ins.oprs[0].offset | SEG_ABS,
output_ins.oprs[1].offset, false);
} else {
/*
* Special `..' EQUs get processed here, except
* `..@' macro processor EQUs which are done above.
*/
if (output_ins.label[0] == '.' &&
output_ins.label[1] == '.' &&
output_ins.label[2] != '@') {
if (output_ins.operands == 1 &&
(output_ins.oprs[0].type & IMMEDIATE)) {
define_label(output_ins.label,
output_ins.oprs[0].segment,
output_ins.oprs[0].offset,
NULL, false, false);
} else if (output_ins.operands == 2
&& (output_ins.oprs[0].type & IMMEDIATE)
&& (output_ins.oprs[0].type & COLON)
&& output_ins.oprs[0].segment == NO_SEG
&& (output_ins.oprs[1].type & IMMEDIATE)
&& output_ins.oprs[1].segment == NO_SEG) {
define_label(output_ins.label,
output_ins.oprs[0].offset | SEG_ABS,
output_ins.oprs[1].offset,
NULL, false, false);
} else
nasm_error(ERR_NONFATAL,
"bad syntax for EQU");
}
nasm_error(ERR_NONFATAL, "bad syntax for EQU");
}
} else { /* instruction isn't an EQU */
int32_t n;

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.
*
@ -426,7 +426,7 @@ static int value_to_extop(expr * vect, extop *eop, int32_t myseg)
return 0;
}
insn *parse_line(int pass, char *buffer, insn *result, ldfunc ldef)
insn *parse_line(int pass, char *buffer, insn *result)
{
bool insn_is_label = false;
struct eval_hints hints;
@ -485,8 +485,8 @@ restart_parse:
* Generally fix things. I think this is right as it is, but
* am still not certain.
*/
ldef(result->label, in_absolute ? absolute.segment : location.segment,
location.offset, NULL, true, false);
define_label(result->label, location.segment,
location.offset, true);
}
}

View file

@ -39,7 +39,7 @@
#ifndef NASM_PARSER_H
#define NASM_PARSER_H
insn *parse_line(int pass, char *buffer, insn *result, ldfunc ldef);
insn *parse_line(int pass, char *buffer, insn *result);
void cleanup_insn(insn *instruction);
#endif

View file

@ -49,6 +49,8 @@
#include "assemble.h"
#include "error.h"
static enum directive_result asm_pragma(const struct pragma *pragma);
/*
* Handle [pragma] directives. [pragma] is generally produced by
* the %pragma preprocessor directive, which simply passes on any
@ -83,7 +85,7 @@
*/
static struct pragma_facility global_pragmas[] =
{
{ "asm", NULL },
{ "asm", asm_pragma },
{ "list", NULL },
{ "file", NULL },
{ "input", NULL },
@ -202,7 +204,7 @@ void process_pragma(char *str)
else
pragma.opcode = directive_find(pragma.opname);
pragma.tail = nasm_skip_spaces(p);
pragma.tail = nasm_trim_spaces(p);
/* Look for a global pragma namespace */
if (search_pragma_list(global_pragmas, NULL, &pragma))
@ -227,3 +229,28 @@ void process_pragma(char *str)
* already defined for future compatibility.
*/
}
/*
* Pragmas for the assembler proper
*/
static enum directive_result asm_pragma(const struct pragma *pragma)
{
switch (pragma->opcode) {
case D_PREFIX:
case D_GPREFIX:
set_label_mangle(LM_GPREFIX, pragma->tail);
return DIRR_OK;
case D_SUFFIX:
case D_GSUFFIX:
set_label_mangle(LM_GSUFFIX, pragma->tail);
return DIRR_OK;
case D_LPREFIX:
set_label_mangle(LM_LPREFIX, pragma->tail);
return DIRR_OK;
case D_LSUFFIX:
set_label_mangle(LM_LSUFFIX, pragma->tail);
return DIRR_OK;
default:
return DIRR_UNKNOWN;
}
}

View file

@ -40,10 +40,10 @@
#include "nasmlib.h"
#include "insns.h"
static int32_t next_seg = 0;
static int32_t next_seg = 2;
void seg_alloc_reset(void)
{
next_seg = 0;
next_seg = 2;
}
int32_t seg_alloc(void)
@ -51,6 +51,5 @@ int32_t seg_alloc(void)
int32_t this_seg = next_seg;
next_seg += 2;
return this_seg;
}

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.
*
@ -40,20 +40,34 @@
#include "compiler.h"
extern char lprefix[PREFIX_MAX];
extern char lpostfix[PREFIX_MAX];
enum mangle_index {
LM_LPREFIX, /* Local variable prefix */
LM_LSUFFIX, /* Local variable suffix */
LM_GPREFIX, /* Global variable prefix */
LM_GSUFFIX /* GLobal variable suffix */
};
enum label_type {
LBL_LOCAL, /* Must be zero */
LBL_GLOBAL,
LBL_STATIC,
LBL_EXTERN,
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);
void define_label(char *label, int32_t segment, int64_t offset, char *special,
bool is_norm, bool isextrn);
void redefine_label(char *label, int32_t segment, int64_t offset, char *special,
bool is_norm, bool isextrn);
void define_common(char *label, int32_t segment, int32_t size, char *special);
void declare_as_global(char *label, char *special);
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);
bool declare_label(const char *label, enum label_type type,
const char *special);
void set_label_mangle(enum mangle_index which, const char *what);
int init_labels(void);
void cleanup_labels(void);
char *local_scope(char *label);
const char *local_scope(const char *label);
extern uint64_t global_offset_changed;

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.
*
@ -48,6 +48,7 @@
#include "preproc.h"
#include "insnsi.h" /* For enum opcode */
#include "directiv.h" /* For enum directive */
#include "labels.h" /* For enum mangle_index, enum label_type */
#include "opflags.h"
#include "regs.h"
@ -61,7 +62,7 @@ struct compile_time {
};
extern struct compile_time official_compile_time;
#define NO_SEG -1L /* null segment value */
#define NO_SEG INT32_C(-1) /* null segment value */
#define SEG_ABS 0x40000000L /* mask for far-absolute segments */
#ifndef PREFIX_MAX
@ -141,11 +142,6 @@ struct out_data {
int64_t relbase; /* Relative base for OUT_RELADDR */
};
/*
* A label-lookup function.
*/
typedef bool (*lfunc)(char *label, int32_t *segment, int64_t *offset);
/*
* And a label-definition function. The boolean parameter
* `is_norm' states whether the label is a `normal' label (which
@ -153,10 +149,7 @@ typedef bool (*lfunc)(char *label, int32_t *segment, int64_t *offset);
* an EQU or a segment-base symbol, which shouldn't.
*/
typedef void (*ldfunc)(char *label, int32_t segment, int64_t offset,
char *special, bool is_norm, bool isextrn);
void define_label(char *label, int32_t segment, int64_t offset,
char *special, bool is_norm, bool isextrn);
char *special, bool is_norm);
/*
* Token types returned by the scanner, in addition to ordinary
@ -904,7 +897,7 @@ struct ofmt {
* 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);
int32_t (*herelabel)(const char *name, enum label_type type, int32_t seg);
/*
* This procedure is called to modify section alignment,

View file

@ -130,13 +130,6 @@ STD: nasm
%endif
%endmacro
%imacro extern 1-*.nolist
%rep %0
[extern %1]
%rotate 1
%endrep
%endmacro
%imacro bits 1+.nolist
[bits %1]
%endmacro
@ -153,6 +146,20 @@ STD: nasm
[bits 64]
%endmacro
%imacro extern 1-*.nolist
%rep %0
[extern %1]
%rotate 1
%endrep
%endmacro
%imacro static 1-*.nolist
%rep %0
[static %1]
%rotate 1
%endrep
%endmacro
%imacro global 1-*.nolist
%rep %0
[global %1]

View file

@ -198,15 +198,15 @@ static void aoutb_init(void)
is_pic = 0x00; /* may become 0x40 */
aout_gotpc_sect = seg_alloc();
define_label("..gotpc", aout_gotpc_sect + 1, 0L, NULL, false, false);
backend_label("..gotpc", aout_gotpc_sect + 1, 0L);
aout_gotoff_sect = seg_alloc();
define_label("..gotoff", aout_gotoff_sect + 1, 0L, NULL, false, false);
backend_label("..gotoff", aout_gotoff_sect + 1, 0L);
aout_got_sect = seg_alloc();
define_label("..got", aout_got_sect + 1, 0L, NULL, false, false);
backend_label("..got", aout_got_sect + 1, 0L);
aout_plt_sect = seg_alloc();
define_label("..plt", aout_plt_sect + 1, 0L, NULL, false, false);
backend_label("..plt", aout_plt_sect + 1, 0L);
aout_sym_sect = seg_alloc();
define_label("..sym", aout_sym_sect + 1, 0L, NULL, false, false);
backend_label("..sym", aout_sym_sect + 1, 0L);
}
#endif

View file

@ -1217,11 +1217,11 @@ static void bin_define_section_labels(void)
/* section.<name>.start */
strcpy(label_name + base_len, ".start");
define_label(label_name, sec->start_index, 0L, NULL, 0, 0);
define_label(label_name, sec->start_index, 0L, false);
/* section.<name>.vstart */
strcpy(label_name + base_len, ".vstart");
define_label(label_name, sec->vstart_index, 0L, NULL, 0, 0);
define_label(label_name, sec->vstart_index, 0L, false);
nasm_free(label_name);
}

View file

@ -198,7 +198,7 @@ static void coff_win64_init(void)
win64 = true;
coff_gen_init();
imagebase_sect = seg_alloc()+1;
define_label(WRT_IMAGEBASE, imagebase_sect, 0, NULL, false, false);
backend_label(WRT_IMAGEBASE, imagebase_sect, 0);
}
static void coff_std_init(void)

View file

@ -124,7 +124,7 @@ static int32_t dbg_add_section(char *name, int pass, int *bits,
whatwecallit, name, tail, pass, seg);
if (section_labels)
define_label(s->name, s->number + 1, 0, NULL, false, false);
backend_label(s->name, s->number + 1, 0);
}
}
return seg;
@ -135,15 +135,16 @@ 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)
static int32_t dbg_herelabel(const char *name, enum label_type type,
int32_t seg)
{
int32_t newseg = seg;
if (subsections_via_symbols && name[0] != 'L')
if (subsections_via_symbols && type != LBL_LOCAL)
newseg += 0x10000;
fprintf(ofile, "herelabel %s (seg %08x) -> %08x\n",
name, seg, newseg);
fprintf(ofile, "herelabel %s type %d (seg %08x) -> %08x\n",
name, type, seg, newseg);
return newseg;
}

View file

@ -337,19 +337,19 @@ static void elf_init(void)
*/
elf_gotpc_sect = seg_alloc();
define_label("..gotpc", elf_gotpc_sect + 1, 0L, NULL, false, false);
backend_label("..gotpc", elf_gotpc_sect + 1, 0L);
elf_gotoff_sect = seg_alloc();
define_label("..gotoff", elf_gotoff_sect + 1, 0L, NULL, false, false);
backend_label("..gotoff", elf_gotoff_sect + 1, 0L);
elf_got_sect = seg_alloc();
define_label("..got", elf_got_sect + 1, 0L, NULL, false, false);
backend_label("..got", elf_got_sect + 1, 0L);
elf_plt_sect = seg_alloc();
define_label("..plt", elf_plt_sect + 1, 0L, NULL, false, false);
backend_label("..plt", elf_plt_sect + 1, 0L);
elf_sym_sect = seg_alloc();
define_label("..sym", elf_sym_sect + 1, 0L, NULL, false, false);
backend_label("..sym", elf_sym_sect + 1, 0L);
elf_gottpoff_sect = seg_alloc();
define_label("..gottpoff", elf_gottpoff_sect + 1, 0L, NULL, false, false);
backend_label("..gottpoff", elf_gottpoff_sect + 1, 0L);
elf_tlsie_sect = seg_alloc();
define_label("..tlsie", elf_tlsie_sect + 1, 0L, NULL, false, false);
backend_label("..tlsie", elf_tlsie_sect + 1, 0L);
def_seg = seg_alloc();
}

View file

@ -808,10 +808,9 @@ static int32_t ieee_segment(char *name, int pass, int *bits)
ieee_seg_needs_update = seg;
if (seg->align >= SEG_ABS)
define_label(name, NO_SEG, seg->align - SEG_ABS,
NULL, false, false);
define_label(name, NO_SEG, seg->align - SEG_ABS, false);
else
define_label(name, seg->index + 1, 0L, NULL, false, false);
define_label(name, seg->index + 1, 0L, false);
ieee_seg_needs_update = NULL;
if (seg->use32)

View file

@ -411,7 +411,7 @@ static void macho_init(void)
/* add special symbol for TLVP */
macho_tlvp_sect = seg_alloc() + 1;
define_label("..tlvp", macho_tlvp_sect, 0L, NULL, false, false);
backend_label("..tlvp", macho_tlvp_sect, 0L);
}
@ -1002,15 +1002,17 @@ static int32_t macho_section(char *name, int pass, int *bits)
return s->index | (s->subsection << 16);
}
static int32_t macho_herelabel(const char *name, int32_t section)
static int32_t macho_herelabel(const char *name, enum label_type type,
int32_t section)
{
struct section *s;
(void)name;
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')
/* No subsection only for local labels */
if (type == LBL_LOCAL)
return section;
s = get_section_by_index(section);
@ -2398,7 +2400,7 @@ static void macho64_init(void)
/* add special symbol for ..gotpcrel */
macho_gotpcrel_sect = seg_alloc() + 1;
define_label("..gotpcrel", macho_gotpcrel_sect, 0L, NULL, false, false);
backend_label("..gotpcrel", macho_gotpcrel_sect, 0L);
}
static const struct dfmt macho64_df_dwarf = {

View file

@ -1540,11 +1540,9 @@ static int32_t obj_segment(char *name, int pass, int *bits)
obj_seg_needs_update = seg;
if (seg->align >= SEG_ABS)
define_label(name, NO_SEG, seg->align - SEG_ABS,
NULL, false, false);
define_label(name, NO_SEG, seg->align - SEG_ABS, false);
else
define_label(name, seg->index + 1, 0L,
NULL, false, false);
define_label(name, seg->index + 1, 0L, false);
obj_seg_needs_update = NULL;
/*
@ -1647,7 +1645,7 @@ obj_directive(enum directive directive, char *value, int pass)
grp->name = NULL;
obj_grp_needs_update = grp;
define_label(v, grp->index + 1, 0L, NULL, false, false);
backend_label(v, grp->index + 1, 0L);
obj_grp_needs_update = NULL;
while (*q) {

View file

@ -5,12 +5,13 @@
;
%pragma output subsections_via_symbols
%pragma asm gprefix _
%pragma asm lprefix L_
bits 32
global foo, bar, quux
%define baz Lbaz
global foo, bar
static quux
foo:
jmp foo