mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-03-19 18:00:23 +08:00
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:
parent
8413e8167a
commit
98578071b9
177
asm/directiv.c
177
asm/directiv.c
@ -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] */
|
||||
|
@ -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
|
||||
|
@ -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 '-':
|
||||
|
533
asm/labels.c
533
asm/labels.c
@ -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(<ab, 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 : "";
|
||||
}
|
||||
|
126
asm/nasm.c
126
asm/nasm.c
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
31
asm/pragma.c
31
asm/pragma.c
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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 = {
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user