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>
This commit is contained in:
H. Peter Anvin 2018-12-18 19:14:40 -08:00
parent 5307832cd1
commit 2965154684
2 changed files with 210 additions and 177 deletions

View file

@ -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;
}
/* 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 */
/* Normal instruction, or RESx */
/* 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)
return -1; /* No match */
isize = calcsize(segment, offset, bits, instruction, temp);
debug_set_type(instruction);
return isize;
}
}

View file

@ -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: