summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2018-12-18 19:14:40 -0800
committerH. Peter Anvin <hpa@zytor.com>2018-12-18 19:14:40 -0800
commit296515468447185af1f310cb2d3a7a8b06996b61 (patch)
tree470a365e16e7d0aa1fa01b480e85475d6da76f3a
parent5307832cd1216faeff74f3322c4d6bb65e44b6e0 (diff)
downloadnasm-296515468447185af1f310cb2d3a7a8b06996b61.tar.gz
assemble_file(): break up this gigantic mess
Break up this gigantic mess which touches way too many layers. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--asm/assemble.c151
-rw-r--r--asm/nasm.c234
2 files changed, 209 insertions, 176 deletions
diff --git a/asm/assemble.c b/asm/assemble.c
index 42509ec6..115eea22 100644
--- a/asm/assemble.c
+++ b/asm/assemble.c
@@ -823,19 +823,133 @@ int64_t assemble(int32_t segment, int64_t start, int bits, insn *instruction)
return data.offset - start;
}
+static void debug_set_db_type(insn *instruction)
+{
+ /* Is this really correct? .operands doesn't mean much for Dx */
+ int32_t typeinfo = TYS_ELEMENTS(instruction->operands);
+
+ switch (instruction->opcode) {
+ case I_DB:
+ typeinfo |= TY_BYTE;
+ break;
+ case I_DW:
+ typeinfo |= TY_WORD;
+ break;
+ case I_DD:
+ if (instruction->eops_float)
+ typeinfo |= TY_FLOAT;
+ else
+ typeinfo |= TY_DWORD;
+ break;
+ case I_DQ:
+ /* What about double? */
+ typeinfo |= TY_QWORD;
+ break;
+ case I_DT:
+ /* What about long double? */
+ typeinfo |= TY_TBYTE;
+ break;
+ case I_DO:
+ typeinfo |= TY_OWORD;
+ break;
+ case I_DY:
+ typeinfo |= TY_YWORD;
+ break;
+ case I_DZ:
+ typeinfo |= TY_ZWORD;
+ break;
+ default:
+ panic();
+ }
+
+ dfmt->debug_typevalue(typeinfo);
+}
+
+static void debug_set_type(insn *instruction)
+{
+ int32_t typeinfo;
+
+ if (opcode_is_resb(instruction->opcode)) {
+ typeinfo = TYS_ELEMENTS(instruction->oprs[0].offset);
+
+ switch (instruction->opcode) {
+ case I_RESB:
+ typeinfo |= TY_BYTE;
+ break;
+ case I_RESW:
+ typeinfo |= TY_WORD;
+ break;
+ case I_RESD:
+ typeinfo |= TY_DWORD;
+ break;
+ case I_RESQ:
+ typeinfo |= TY_QWORD;
+ break;
+ case I_REST:
+ typeinfo |= TY_TBYTE;
+ break;
+ case I_RESO:
+ typeinfo |= TY_OWORD;
+ break;
+ case I_RESY:
+ typeinfo |= TY_YWORD;
+ break;
+ case I_RESZ:
+ typeinfo |= TY_ZWORD;
+ break;
+ default:
+ panic();
+ }
+ } else {
+ typeinfo = TY_LABEL;
+ }
+
+ dfmt->debug_typevalue(typeinfo);
+}
+
+
+/* Proecess an EQU directive */
+static void define_equ(insn * instruction)
+{
+ if (!instruction->label) {
+ nasm_nonfatal("EQU not preceded by label");
+ } else if (instruction->operands == 1 &&
+ (instruction->oprs[0].type & IMMEDIATE) &&
+ instruction->oprs[0].wrt == NO_SEG) {
+ define_label(instruction->label,
+ instruction->oprs[0].segment,
+ instruction->oprs[0].offset, false);
+ } else if (instruction->operands == 2
+ && (instruction->oprs[0].type & IMMEDIATE)
+ && (instruction->oprs[0].type & COLON)
+ && instruction->oprs[0].segment == NO_SEG
+ && instruction->oprs[0].wrt == NO_SEG
+ && (instruction->oprs[1].type & IMMEDIATE)
+ && instruction->oprs[1].segment == NO_SEG
+ && instruction->oprs[1].wrt == NO_SEG) {
+ define_label(instruction->label,
+ instruction->oprs[0].offset | SEG_ABS,
+ instruction->oprs[1].offset, false);
+ } else {
+ nasm_nonfatal("bad syntax for EQU");
+ }
+}
+
int64_t insn_size(int32_t segment, int64_t offset, int bits, insn *instruction)
{
const struct itemplate *temp;
enum match_result m;
+ int64_t isize = 0;
- if (instruction->opcode == I_none)
+ if (instruction->opcode == I_none) {
return 0;
-
- if (opcode_is_db(instruction->opcode)) {
+ } else if (instruction->opcode == I_EQU) {
+ define_equ(instruction);
+ return 0;
+ } else if (opcode_is_db(instruction->opcode)) {
extop *e;
- int32_t isize, osize, wsize;
+ int32_t osize, wsize;
- isize = 0;
wsize = db_bytes(instruction->opcode);
nasm_assert(wsize > 0);
@@ -855,10 +969,10 @@ int64_t insn_size(int32_t segment, int64_t offset, int bits, insn *instruction)
align += wsize;
isize += osize + align;
}
- return isize;
- }
- if (instruction->opcode == I_INCBIN) {
+ debug_set_db_type(instruction);
+ return isize;
+ } else if (instruction->opcode == I_INCBIN) {
const char *fname = instruction->eops->stringval;
off_t len;
@@ -885,17 +999,20 @@ int64_t insn_size(int32_t segment, int64_t offset, int bits, insn *instruction)
instruction->times = 1; /* Tell the upper layer to not iterate */
return len;
- }
+ } else {
+ /* Normal instruction, or RESx */
- /* Check to see if we need an address-size prefix */
- add_asp(instruction, bits);
+ /* Check to see if we need an address-size prefix */
+ add_asp(instruction, bits);
- m = find_match(&temp, instruction, segment, offset, bits);
- if (m == MOK_GOOD) {
- /* we've matched an instruction. */
- return calcsize(segment, offset, bits, instruction, temp);
- } else {
- return -1; /* didn't match any instruction */
+ m = find_match(&temp, instruction, segment, offset, bits);
+ if (m != MOK_GOOD)
+ return -1; /* No match */
+
+ isize = calcsize(segment, offset, bits, instruction, temp);
+ debug_set_type(instruction);
+
+ return isize;
}
}
diff --git a/asm/nasm.c b/asm/nasm.c
index e0c23af3..ae5e8b91 100644
--- a/asm/nasm.c
+++ b/asm/nasm.c
@@ -1410,11 +1410,83 @@ static void parse_cmdline(int argc, char **argv, int pass)
}
}
+static void forward_refs(insn *instruction)
+{
+ int i;
+ struct forwrefinfo *fwinf;
+
+ instruction->forw_ref = false;
+
+ if (!optimizing.level)
+ return; /* For -O0 don't bother */
+
+ if (!forwref)
+ return;
+
+ if (forwref->lineno != globallineno)
+ return;
+
+ instruction->forw_ref = true;
+ do {
+ instruction->oprs[forwref->operand].opflags |= OPFLAG_FORWARD;
+ forwref = saa_rstruct(forwrefs);
+ } while (forwref && forwref->lineno == globallineno);
+
+ if (!pass_first())
+ return;
+
+ for (i = 0; i < instruction->operands; i++) {
+ if (instruction->oprs[i].opflags & OPFLAG_FORWARD) {
+ fwinf = saa_wstruct(forwrefs);
+ fwinf->lineno = globallineno;
+ fwinf->operand = i;
+ }
+ }
+}
+
+static void process_insn(insn *instruction)
+{
+ int32_t n;
+ int64_t l;
+
+ if (!instruction->times)
+ return; /* Nothing to do... */
+
+ nasm_assert(instruction->times > 0);
+
+ /*
+ * NOTE: insn_size() can change instruction->times
+ * (usually to 1) when called.
+ */
+ if (!pass_final()) {
+ for (n = 1; n <= instruction->times; n++) {
+ l = insn_size(location.segment, location.offset,
+ globalbits, instruction);
+ if (l != -1) /* l == -1 -> invalid instruction */
+ increment_offset(l);
+ }
+ } else {
+ l = assemble(location.segment, location.offset,
+ globalbits, instruction);
+ /* We can't get an invalid instruction here */
+ increment_offset(l);
+
+ if (instruction->times > 1) {
+ lfmt->uplevel(LIST_TIMES);
+ for (n = 2; n <= instruction->times; n++) {
+ l = assemble(location.segment, location.offset,
+ globalbits, instruction);
+ increment_offset(l);
+ }
+ lfmt->downlevel(LIST_TIMES);
+ }
+ }
+}
+
static void assemble_file(const char *fname, struct strlist *depend_list)
{
char *line;
insn output_ins;
- int i;
uint64_t prev_offset_changed;
int64_t stall_count = 0; /* Make sure we make forward progress... */
@@ -1498,164 +1570,8 @@ static void assemble_file(const char *fname, struct strlist *depend_list)
/* Not a directive, or even something that starts with [ */
parse_line(line, &output_ins);
-
- if (optimizing.level > 0) {
- if (forwref != NULL && globallineno == forwref->lineno) {
- output_ins.forw_ref = true;
- do {
- output_ins.oprs[forwref->operand].opflags |= OPFLAG_FORWARD;
- forwref = saa_rstruct(forwrefs);
- } while (forwref != NULL
- && forwref->lineno == globallineno);
- } else
- output_ins.forw_ref = false;
-
- if (output_ins.forw_ref) {
- if (pass_first()) {
- for (i = 0; i < output_ins.operands; i++) {
- if (output_ins.oprs[i].opflags & OPFLAG_FORWARD) {
- struct forwrefinfo *fwinf = (struct forwrefinfo *)saa_wstruct(forwrefs);
- fwinf->lineno = globallineno;
- fwinf->operand = i;
- }
- }
- }
- }
- }
-
- /* forw_ref */
- if (output_ins.opcode == I_EQU) {
- if (!output_ins.label) {
- nasm_nonfatal("EQU not preceded by label");
- } else 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 {
- nasm_nonfatal("bad syntax for EQU");
- }
- } else { /* instruction isn't an EQU */
- int32_t n;
-
- nasm_assert(output_ins.times >= 0);
-
- for (n = 1; n <= output_ins.times; n++) {
- if (!pass_final()) {
- int64_t l = insn_size(location.segment,
- location.offset,
- globalbits, &output_ins);
-
- /* if (using_debug_info) && output_ins.opcode != -1) */
- if (using_debug_info)
- { /* fbk 03/25/01 */
- /* this is done here so we can do debug type info */
- int32_t typeinfo =
- TYS_ELEMENTS(output_ins.operands);
- switch (output_ins.opcode) {
- case I_RESB:
- typeinfo =
- TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_BYTE;
- break;
- case I_RESW:
- typeinfo =
- TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_WORD;
- break;
- case I_RESD:
- typeinfo =
- TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_DWORD;
- break;
- case I_RESQ:
- typeinfo =
- TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_QWORD;
- break;
- case I_REST:
- typeinfo =
- TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_TBYTE;
- break;
- case I_RESO:
- typeinfo =
- TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_OWORD;
- break;
- case I_RESY:
- typeinfo =
- TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_YWORD;
- break;
- case I_RESZ:
- typeinfo =
- TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_ZWORD;
- break;
- case I_DB:
- typeinfo |= TY_BYTE;
- break;
- case I_DW:
- typeinfo |= TY_WORD;
- break;
- case I_DD:
- if (output_ins.eops_float)
- typeinfo |= TY_FLOAT;
- else
- typeinfo |= TY_DWORD;
- break;
- case I_DQ:
- typeinfo |= TY_QWORD;
- break;
- case I_DT:
- typeinfo |= TY_TBYTE;
- break;
- case I_DO:
- typeinfo |= TY_OWORD;
- break;
- case I_DY:
- typeinfo |= TY_YWORD;
- break;
- case I_DZ:
- typeinfo |= TY_ZWORD;
- break;
- default:
- typeinfo = TY_LABEL;
- break;
- }
-
- dfmt->debug_typevalue(typeinfo);
- }
-
- /*
- * For INCBIN, let the code in assemble
- * handle TIMES, so we don't have to read the
- * input file over and over.
- */
- if (l != -1) {
- increment_offset(l);
- }
- /*
- * else l == -1 => invalid instruction, which will be
- * flagged as an error on pass 2
- */
- } else {
- if (n == 2)
- lfmt->uplevel(LIST_TIMES);
- increment_offset(assemble(location.segment,
- location.offset,
- globalbits, &output_ins));
- }
- } /* not an EQU */
- }
- if (output_ins.times > 1)
- lfmt->downlevel(LIST_TIMES);
-
+ forward_refs(&output_ins);
+ process_insn(&output_ins);
cleanup_insn(&output_ins);
end_of_line: