summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2018-06-11 14:54:14 -0700
committerH. Peter Anvin <hpa@linux.intel.com>2018-06-11 14:54:14 -0700
commit734824823e764addd52c085a647fda5faa29e504 (patch)
tree3c1197c7d1b5cbc73543968127289f819a03538e
parent0599034321c22b6fa84c76a08866e6de36b02f77 (diff)
downloadnasm-734824823e764addd52c085a647fda5faa29e504.tar.gz
Unbreak special segment symbols, unbreak COMMON
Recent changes broke: 1. Backend-provided special segments, due to seg_alloc() getting reset. 2. COMMON; the old code would pass size in the "offset" *without* setting it in the label structure. Containing all this information in the label structure requires another field. Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r--asm/directiv.c22
-rw-r--r--asm/labels.c29
-rw-r--r--asm/nasm.c5
-rw-r--r--asm/segalloc.c15
-rw-r--r--include/nasmlib.h3
5 files changed, 52 insertions, 22 deletions
diff --git a/asm/directiv.c b/asm/directiv.c
index 567a6bd3..53c1917c 100644
--- a/asm/directiv.c
+++ b/asm/directiv.c
@@ -317,17 +317,24 @@ bool process_directives(char *directive)
char *sizestr;
bool rn_error;
+ if (*value == '$')
+ value++; /* skip initial $ if present */
+
q = value;
- if (!isidstart(*q))
+ if (!isidstart(*q)) {
validid = false;
- while (*q && *q != ':' && !nasm_isspace(*q)) {
- if (!isidchar(*q))
- validid = false;
+ } else {
q++;
+ while (*q && *q != ':' && !nasm_isspace(*q)) {
+ if (!isidchar(*q))
+ validid = false;
+ q++;
+ }
}
if (!validid) {
nasm_error(ERR_NONFATAL,
- "identifier expected after %s", directive);
+ "identifier expected after %s, got `%s'",
+ directive, value);
break;
}
@@ -358,14 +365,11 @@ bool process_directives(char *directive)
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);
+ define_label(value, seg_alloc(), size, false);
break;
}
diff --git a/asm/labels.c b/asm/labels.c
index 2275bdb7..94a57ac2 100644
--- a/asm/labels.c
+++ b/asm/labels.c
@@ -93,6 +93,7 @@ union label { /* actual label structures */
struct {
int32_t segment;
int64_t offset;
+ int64_t size;
char *label, *mangled, *special;
enum label_type type, mangled_type;
bool defined;
@@ -135,14 +136,15 @@ static bool initialized = false;
static void out_symdef(union label *lptr)
{
int backend_type;
+ int64_t backend_offset;
/* 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:
+ case LBL_COMMON:
if (lptr->defn.special)
ofmt->symdef(lptr->defn.label, 0, 0, 3, lptr->defn.special);
break;
@@ -159,12 +161,15 @@ static void out_symdef(union label *lptr)
switch(lptr->defn.type) {
case LBL_GLOBAL:
backend_type = 1;
+ backend_offset = lptr->defn.offset;
break;
case LBL_COMMON:
backend_type = 2;
+ backend_offset = lptr->defn.size;
break;
default:
backend_type = 0;
+ backend_offset = lptr->defn.offset;
break;
}
@@ -172,7 +177,7 @@ static void out_symdef(union label *lptr)
mangle_label_name(lptr);
ofmt->symdef(lptr->defn.mangled, lptr->defn.segment,
- lptr->defn.offset, backend_type,
+ backend_offset, backend_type,
lptr->defn.special);
/*
@@ -348,9 +353,6 @@ static bool declare_label_lptr(union label *lptr,
if (special && !special[0])
special = NULL;
- printf("declare_label %s type %d special %s\n",
- lptr->defn.label, lptr->defn.type, lptr->defn.special);
-
if (lptr->defn.type == type ||
(pass0 == 0 && lptr->defn.type == LBL_LOCAL)) {
lptr->defn.type = type;
@@ -407,6 +409,7 @@ void define_label(const char *label, int32_t segment,
{
union label *lptr;
bool created, changed;
+ int64_t size;
/*
* Phase errors here can be one of two types: a new label appears,
@@ -428,13 +431,20 @@ void define_label(const char *label, int32_t segment,
if (ismagic(label) && lptr->defn.type == LBL_LOCAL)
lptr->defn.type = LBL_SPECIAL;
-
+
if (!islocal(label) && normal) {
prevlabel = lptr->defn.label;
}
+ if (lptr->defn.type == LBL_COMMON) {
+ size = offset;
+ offset = 0;
+ } else {
+ size = 0; /* This is a hack... */
+ }
+
changed = !lptr->defn.defined || lptr->defn.segment != segment ||
- lptr->defn.offset != offset;
+ lptr->defn.offset != offset || lptr->defn.size != size;
global_offset_changed += changed;
/*
@@ -448,6 +458,7 @@ void define_label(const char *label, int32_t segment,
lptr->defn.segment = segment;
lptr->defn.offset = offset;
+ lptr->defn.size = size;
lptr->defn.defined = true;
out_symdef(lptr);
@@ -521,7 +532,7 @@ static void init_block(union label *blk)
static char * safe_alloc perm_alloc(size_t len)
{
char *p;
-
+
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);
@@ -558,7 +569,7 @@ perm_copy3(const char *s1, const char *s2, const char *s3)
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);
diff --git a/asm/nasm.c b/asm/nasm.c
index 5fbedae1..6db5cce2 100644
--- a/asm/nasm.c
+++ b/asm/nasm.c
@@ -1345,6 +1345,9 @@ static void assemble_file(const char *fname, StrList **depend_ptr)
break;
}
+ /* Any segment numbers allocated before this point are permanent */
+ seg_alloc_setup_done();
+
pass_max = prev_offset_changed = (INT_MAX >> 1) + 2; /* Almost unlimited */
for (passn = 1; pass0 <= 2; passn++) {
pass1 = pass0 == 2 ? 2 : 1; /* 1, 1, 1, ..., 1, 2 */
@@ -1426,7 +1429,7 @@ static void assemble_file(const char *fname, StrList **depend_ptr)
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) {
diff --git a/asm/segalloc.c b/asm/segalloc.c
index 5b4ea4bb..56544b42 100644
--- a/asm/segalloc.c
+++ b/asm/segalloc.c
@@ -40,10 +40,21 @@
#include "nasmlib.h"
#include "insns.h"
-static int32_t next_seg = 2;
+static int32_t next_seg = 2;
+static int32_t seg_start = 2;
+
void seg_alloc_reset(void)
{
- next_seg = 2;
+ next_seg = seg_start;
+}
+
+/*
+ * This gets called after special segments are allocated, typically by
+ * backends; this only gets done once.
+ */
+void seg_alloc_setup_done(void)
+{
+ seg_start = next_seg;
}
int32_t seg_alloc(void)
diff --git a/include/nasmlib.h b/include/nasmlib.h
index c6ca3373..2cfe9a37 100644
--- a/include/nasmlib.h
+++ b/include/nasmlib.h
@@ -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.
*
@@ -194,6 +194,7 @@ int64_t readstrnum(char *str, int length, bool *warn);
* seg_alloc: allocate a hitherto unused segment number.
*/
void seg_alloc_reset(void);
+void seg_alloc_setup_done(void);
int32_t seg_alloc(void);
/*