Compare commits
4 Commits
eab2202f23
...
main
Author | SHA1 | Date | |
---|---|---|---|
7cefc3564d | |||
c848995ad6 | |||
5272fdb227 | |||
0acc3f27f3 |
58
src/ast.h
58
src/ast.h
@ -5,6 +5,7 @@
|
|||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
#include "tokenlist.h"
|
#include "tokenlist.h"
|
||||||
|
#include <assert.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
@ -79,6 +80,22 @@ typedef struct opcode_encoding {
|
|||||||
size_t len;
|
size_t len;
|
||||||
} opcode_encoding_t;
|
} opcode_encoding_t;
|
||||||
|
|
||||||
|
typedef struct instruction {
|
||||||
|
bool has_reference;
|
||||||
|
opcode_encoding_t encoding;
|
||||||
|
int64_t address;
|
||||||
|
} instruction_t;
|
||||||
|
|
||||||
|
typedef struct reference {
|
||||||
|
int64_t offset;
|
||||||
|
int64_t address;
|
||||||
|
operand_size_t size;
|
||||||
|
} reference_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int64_t address;
|
||||||
|
} label_t;
|
||||||
|
|
||||||
struct ast_node {
|
struct ast_node {
|
||||||
node_id_t id;
|
node_id_t id;
|
||||||
tokenlist_entry_t *token_entry;
|
tokenlist_entry_t *token_entry;
|
||||||
@ -89,22 +106,37 @@ struct ast_node {
|
|||||||
union {
|
union {
|
||||||
register_t reg;
|
register_t reg;
|
||||||
number_t number;
|
number_t number;
|
||||||
struct {
|
instruction_t instruction;
|
||||||
bool has_reference;
|
reference_t reference;
|
||||||
opcode_encoding_t encoding;
|
label_t label;
|
||||||
int64_t address;
|
|
||||||
} instruction;
|
|
||||||
struct {
|
|
||||||
int64_t offset;
|
|
||||||
int64_t address;
|
|
||||||
operand_size_t size;
|
|
||||||
} reference;
|
|
||||||
struct {
|
|
||||||
int64_t address;
|
|
||||||
} label;
|
|
||||||
} value;
|
} value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline register_t *ast_node_register_value(ast_node_t *node) {
|
||||||
|
assert(node->id == NODE_REGISTER);
|
||||||
|
return &node->value.reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline number_t *ast_node_number_value(ast_node_t *node) {
|
||||||
|
assert(node->id == NODE_NUMBER);
|
||||||
|
return &node->value.number;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline instruction_t *ast_node_instruction_value(ast_node_t *node) {
|
||||||
|
assert(node->id == NODE_INSTRUCTION);
|
||||||
|
return &node->value.instruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline reference_t *ast_node_reference_value(ast_node_t *node) {
|
||||||
|
assert(node->id == NODE_LABEL_REFERENCE);
|
||||||
|
return &node->value.reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline label_t *ast_node_label_value(ast_node_t *node) {
|
||||||
|
assert(node->id == NODE_LABEL);
|
||||||
|
return &node->value.label;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Allocates a new AST node
|
* @brief Allocates a new AST node
|
||||||
*
|
*
|
||||||
|
@ -138,8 +138,128 @@ opcode_data_t *const opcodes[] = {
|
|||||||
{ .kind = OPERAND_REGISTER, .size = OPERAND_SIZE_64 },
|
{ .kind = OPERAND_REGISTER, .size = OPERAND_SIZE_64 },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// CALL rel32
|
||||||
|
&(opcode_data_t) {
|
||||||
|
.mnemonic = "call",
|
||||||
|
.opcode = 0xE8,
|
||||||
|
.opcode_extension = opcode_extension_none,
|
||||||
|
.encoding_class = ENCODING_DEFAULT,
|
||||||
|
.operand_count = 1,
|
||||||
|
.operands = {
|
||||||
|
{ .kind = OPERAND_IMMEDIATE, .size = OPERAND_SIZE_32 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// CALL reg64
|
||||||
|
&(opcode_data_t) {
|
||||||
|
.mnemonic = "call",
|
||||||
|
.opcode = 0xFF,
|
||||||
|
.opcode_extension = 2,
|
||||||
|
.encoding_class = ENCODING_DEFAULT,
|
||||||
|
.rex_w_prefix = true,
|
||||||
|
.operand_count = 1,
|
||||||
|
.operands = {
|
||||||
|
{ .kind = OPERAND_REGISTER, .size = OPERAND_SIZE_64 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// CALL mem64
|
||||||
|
&(opcode_data_t) {
|
||||||
|
.mnemonic = "call",
|
||||||
|
.opcode = 0xFF,
|
||||||
|
.opcode_extension = 2,
|
||||||
|
.encoding_class = ENCODING_DEFAULT,
|
||||||
|
.rex_w_prefix = true,
|
||||||
|
.operand_count = 1,
|
||||||
|
.operands = {
|
||||||
|
{ .kind = OPERAND_MEMORY, .size = OPERAND_SIZE_64 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// JMP rel8 (short jump)
|
||||||
|
&(opcode_data_t) {
|
||||||
|
.mnemonic = "jmp",
|
||||||
|
.opcode = 0xEB,
|
||||||
|
.opcode_extension = opcode_extension_none,
|
||||||
|
.encoding_class = ENCODING_DEFAULT,
|
||||||
|
.operand_count = 1,
|
||||||
|
.operands = {
|
||||||
|
{ .kind = OPERAND_IMMEDIATE, .size = OPERAND_SIZE_8 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// JMP rel16
|
||||||
|
&(opcode_data_t) {
|
||||||
|
.mnemonic = "jmp",
|
||||||
|
.opcode = 0xE9,
|
||||||
|
.opcode_extension = opcode_extension_none,
|
||||||
|
.encoding_class = ENCODING_DEFAULT,
|
||||||
|
.operand_size_prefix = true,
|
||||||
|
.operand_count = 1,
|
||||||
|
.operands = {
|
||||||
|
{ .kind = OPERAND_IMMEDIATE, .size = OPERAND_SIZE_16 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// JMP reg16
|
||||||
|
&(opcode_data_t) {
|
||||||
|
.mnemonic = "jmp",
|
||||||
|
.opcode = 0xFF,
|
||||||
|
.opcode_extension = 4,
|
||||||
|
.encoding_class = ENCODING_DEFAULT,
|
||||||
|
.operand_size_prefix = true,
|
||||||
|
.operand_count = 1,
|
||||||
|
.operands = {
|
||||||
|
{ .kind = OPERAND_REGISTER, .size = OPERAND_SIZE_16 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// JMP rel32 (near jump)
|
||||||
|
&(opcode_data_t) {
|
||||||
|
.mnemonic = "jmp",
|
||||||
|
.opcode = 0xE9,
|
||||||
|
.opcode_extension = opcode_extension_none,
|
||||||
|
.encoding_class = ENCODING_DEFAULT,
|
||||||
|
.operand_count = 1,
|
||||||
|
.operands = {
|
||||||
|
{ .kind = OPERAND_IMMEDIATE, .size = OPERAND_SIZE_32 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// JMP reg32
|
||||||
|
&(opcode_data_t) {
|
||||||
|
.mnemonic = "jmp",
|
||||||
|
.opcode = 0xFF,
|
||||||
|
.opcode_extension = 4,
|
||||||
|
.encoding_class = ENCODING_DEFAULT,
|
||||||
|
.operand_count = 1,
|
||||||
|
.operands = {
|
||||||
|
{ .kind = OPERAND_REGISTER, .size = OPERAND_SIZE_32 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// JMP reg64
|
||||||
|
&(opcode_data_t) {
|
||||||
|
.mnemonic = "jmp",
|
||||||
|
.opcode = 0xFF,
|
||||||
|
.opcode_extension = 4,
|
||||||
|
.encoding_class = ENCODING_DEFAULT,
|
||||||
|
.rex_w_prefix = true,
|
||||||
|
.operand_count = 1,
|
||||||
|
.operands = {
|
||||||
|
{ .kind = OPERAND_REGISTER, .size = OPERAND_SIZE_64 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// JMP mem64
|
||||||
|
&(opcode_data_t) {
|
||||||
|
.mnemonic = "jmp",
|
||||||
|
.opcode = 0xFF,
|
||||||
|
.opcode_extension = 4,
|
||||||
|
.encoding_class = ENCODING_DEFAULT,
|
||||||
|
.rex_w_prefix = true,
|
||||||
|
.operand_count = 1,
|
||||||
|
.operands = {
|
||||||
|
{ .kind = OPERAND_MEMORY, .size = OPERAND_SIZE_64 },
|
||||||
|
},
|
||||||
|
},
|
||||||
nullptr,
|
nullptr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ bool is_operand_match(operand_info_t *info, ast_node_t *operand) {
|
|||||||
switch (info->kind) {
|
switch (info->kind) {
|
||||||
case OPERAND_REGISTER:
|
case OPERAND_REGISTER:
|
||||||
return operand->id == NODE_REGISTER &&
|
return operand->id == NODE_REGISTER &&
|
||||||
operand->value.reg.size == info->size;
|
ast_node_register_value(operand)->size == info->size;
|
||||||
case OPERAND_MEMORY:
|
case OPERAND_MEMORY:
|
||||||
return operand->id == NODE_MEMORY;
|
return operand->id == NODE_MEMORY;
|
||||||
case OPERAND_IMMEDIATE: {
|
case OPERAND_IMMEDIATE: {
|
||||||
@ -278,13 +278,10 @@ bool is_operand_match(operand_info_t *info, ast_node_t *operand) {
|
|||||||
ast_node_t *child = operand->children[0];
|
ast_node_t *child = operand->children[0];
|
||||||
|
|
||||||
if (child->id == NODE_NUMBER)
|
if (child->id == NODE_NUMBER)
|
||||||
return (child->value.number.size & info->size) > 0;
|
return (ast_node_number_value(child)->size & info->size) > 0;
|
||||||
else if (child->id == NODE_LABEL_REFERENCE)
|
else if (child->id == NODE_LABEL_REFERENCE) {
|
||||||
return info->size == OPERAND_SIZE_32;
|
return info->size &= ast_node_reference_value(child)->size;
|
||||||
// FIXME: first pass should give us information about the distance of
|
}
|
||||||
// the label reference so we can pick a size more appropriately instead
|
|
||||||
// of just defaulting to 32 bits
|
|
||||||
break;
|
|
||||||
} // end OPERAND_IMMEDIATE case
|
} // end OPERAND_IMMEDIATE case
|
||||||
}
|
}
|
||||||
assert(false && "unreachable");
|
assert(false && "unreachable");
|
||||||
@ -340,7 +337,7 @@ error_t *encode_one_register_in_opcode(encoder_t *encoder,
|
|||||||
(void)encoder;
|
(void)encoder;
|
||||||
(void)opcode;
|
(void)opcode;
|
||||||
|
|
||||||
register_id_t id = operands->children[0]->value.reg.id;
|
register_id_t id = ast_node_register_value(operands->children[0])->id;
|
||||||
encoding->buffer[encoding->len - 1] |= id & 0b111;
|
encoding->buffer[encoding->len - 1] |= id & 0b111;
|
||||||
if ((id & 0b1000) > 0) {
|
if ((id & 0b1000) > 0) {
|
||||||
*rex |= rex_prefix_r;
|
*rex |= rex_prefix_r;
|
||||||
@ -355,7 +352,7 @@ error_t *encode_one_register(encoder_t *encoder, opcode_data_t *opcode,
|
|||||||
assert(operands->len == 1);
|
assert(operands->len == 1);
|
||||||
assert(operands->children[0]->id == NODE_REGISTER);
|
assert(operands->children[0]->id == NODE_REGISTER);
|
||||||
|
|
||||||
register_id_t id = operands->children[0]->value.reg.id;
|
register_id_t id = ast_node_register_value(operands->children[0])->id;
|
||||||
|
|
||||||
uint8_t modrm = modrm_mod_register;
|
uint8_t modrm = modrm_mod_register;
|
||||||
|
|
||||||
@ -389,9 +386,9 @@ error_t *encode_one_immediate(encoder_t *encoder, opcode_data_t *opcode,
|
|||||||
assert(immediate->id == NODE_NUMBER ||
|
assert(immediate->id == NODE_NUMBER ||
|
||||||
immediate->id == NODE_LABEL_REFERENCE);
|
immediate->id == NODE_LABEL_REFERENCE);
|
||||||
|
|
||||||
|
operand_size_t size = opcode->operands[0].size;
|
||||||
if (immediate->id == NODE_NUMBER) {
|
if (immediate->id == NODE_NUMBER) {
|
||||||
uint64_t value = immediate->value.number.value;
|
uint64_t value = ast_node_number_value(immediate)->value;
|
||||||
operand_size_t size = opcode->operands[0].size;
|
|
||||||
error_t *err = nullptr;
|
error_t *err = nullptr;
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case OPERAND_SIZE_8:
|
case OPERAND_SIZE_8:
|
||||||
@ -411,10 +408,21 @@ error_t *encode_one_immediate(encoder_t *encoder, opcode_data_t *opcode,
|
|||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
} else {
|
} else {
|
||||||
// FIXME: this still assumes references are always 32 bit
|
reference_t *reference = ast_node_reference_value(immediate);
|
||||||
uint32_t value = 0xDEADBEEF;
|
switch (size) {
|
||||||
return bytes_append_uint32(encoding, value);
|
case OPERAND_SIZE_64:
|
||||||
|
return bytes_append_uint64(encoding, reference->address);
|
||||||
|
case OPERAND_SIZE_32:
|
||||||
|
return bytes_append_uint32(encoding, reference->offset);
|
||||||
|
case OPERAND_SIZE_16:
|
||||||
|
return bytes_append_uint16(encoding, reference->offset);
|
||||||
|
case OPERAND_SIZE_8:
|
||||||
|
return bytes_append_uint8(encoding, reference->offset);
|
||||||
|
default:
|
||||||
|
assert(false && "intentionally unhandled");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t *encode_one_memory(encoder_t *encoder, opcode_data_t *opcode,
|
error_t *encode_one_memory(encoder_t *encoder, opcode_data_t *opcode,
|
||||||
@ -483,7 +491,8 @@ error_t *encoder_encode_instruction(encoder_t *encoder,
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
// produce the actual encoding output in the NODE_INSTRUCTION value
|
// produce the actual encoding output in the NODE_INSTRUCTION value
|
||||||
uint8_t *output = instruction->value.instruction.encoding.buffer;
|
instruction_t *instruction_value = ast_node_instruction_value(instruction);
|
||||||
|
uint8_t *output = instruction_value->encoding.buffer;
|
||||||
size_t output_len = 0;
|
size_t output_len = 0;
|
||||||
|
|
||||||
// Handle prefixes
|
// Handle prefixes
|
||||||
@ -502,11 +511,17 @@ error_t *encoder_encode_instruction(encoder_t *encoder,
|
|||||||
memcpy(output + output_len, encoding->buffer, encoding->len);
|
memcpy(output + output_len, encoding->buffer, encoding->len);
|
||||||
output_len += encoding->len;
|
output_len += encoding->len;
|
||||||
|
|
||||||
instruction->value.instruction.encoding.len = output_len;
|
instruction_value->encoding.len = output_len;
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initial guess for instruction size of instructions that contain a label
|
||||||
|
* reference
|
||||||
|
*/
|
||||||
|
constexpr size_t instruction_size_estimate = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform the initial pass over the AST.
|
* Perform the initial pass over the AST.
|
||||||
*
|
*
|
||||||
@ -518,7 +533,6 @@ error_t *encoder_encode_instruction(encoder_t *encoder,
|
|||||||
* - determine estimated addresses of each statement
|
* - determine estimated addresses of each statement
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
constexpr size_t instruction_size_estimate = 10;
|
|
||||||
error_t *encoder_first_pass(encoder_t *encoder) {
|
error_t *encoder_first_pass(encoder_t *encoder) {
|
||||||
ast_node_t *root = encoder->ast;
|
ast_node_t *root = encoder->ast;
|
||||||
assert(root->id == NODE_PROGRAM);
|
assert(root->id == NODE_PROGRAM);
|
||||||
@ -532,19 +546,21 @@ error_t *encoder_first_pass(encoder_t *encoder) {
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (statement->id == NODE_INSTRUCTION &&
|
if (statement->id == NODE_INSTRUCTION &&
|
||||||
statement->value.instruction.has_reference == false) {
|
ast_node_instruction_value(statement)->has_reference == false) {
|
||||||
err = encoder_encode_instruction(encoder, statement);
|
err = encoder_encode_instruction(encoder, statement);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
statement->value.instruction.address = address;
|
instruction_t *instruction = ast_node_instruction_value(statement);
|
||||||
address += statement->value.instruction.encoding.len;
|
instruction->address = address;
|
||||||
|
address += instruction->encoding.len;
|
||||||
} else if (statement->id == NODE_INSTRUCTION) {
|
} else if (statement->id == NODE_INSTRUCTION) {
|
||||||
statement->value.instruction.encoding.len =
|
instruction_t *instruction = ast_node_instruction_value(statement);
|
||||||
instruction_size_estimate;
|
instruction->encoding.len = instruction_size_estimate;
|
||||||
statement->value.instruction.address = address;
|
instruction->address = address;
|
||||||
address += instruction_size_estimate;
|
address += instruction_size_estimate;
|
||||||
} else if (statement->id == NODE_LABEL) {
|
} else if (statement->id == NODE_LABEL) {
|
||||||
statement->value.instruction.address = address;
|
label_t *label = ast_node_label_value(statement);
|
||||||
|
label->address = address;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,18 +583,18 @@ operand_size_t signed_to_size_mask(int64_t value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int64_t statement_offset(ast_node_t *from, ast_node_t *to) {
|
int64_t statement_offset(ast_node_t *from, ast_node_t *to) {
|
||||||
assert(from->id == NODE_LABEL || from->id == NODE_INSTRUCTION);
|
assert(from->id == NODE_INSTRUCTION);
|
||||||
assert(to->id == NODE_LABEL || to->id == NODE_INSTRUCTION);
|
assert(to->id == NODE_LABEL);
|
||||||
|
|
||||||
int64_t from_addr =
|
instruction_t *instruction = ast_node_instruction_value(from);
|
||||||
from->value.instruction.address + from->value.instruction.encoding.len;
|
int64_t from_addr = instruction->address + instruction->encoding.len;
|
||||||
int64_t to_addr = to->value.instruction.address;
|
int64_t to_addr = ast_node_label_value(to)->address;
|
||||||
|
|
||||||
return to_addr - from_addr;
|
return to_addr - from_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t *encoder_collect_label_info(encoder_t *encoder, ast_node_t *node,
|
error_t *encoder_collect_reference_info(encoder_t *encoder, ast_node_t *node,
|
||||||
ast_node_t *statement) {
|
ast_node_t *statement) {
|
||||||
assert(statement->id == NODE_INSTRUCTION);
|
assert(statement->id == NODE_INSTRUCTION);
|
||||||
if (node->id == NODE_LABEL_REFERENCE) {
|
if (node->id == NODE_LABEL_REFERENCE) {
|
||||||
const char *name = node->token_entry->token.value;
|
const char *name = node->token_entry->token.value;
|
||||||
@ -587,7 +603,7 @@ error_t *encoder_collect_label_info(encoder_t *encoder, ast_node_t *node,
|
|||||||
symbol->statement->id == NODE_LABEL);
|
symbol->statement->id == NODE_LABEL);
|
||||||
|
|
||||||
int64_t offset = statement_offset(statement, symbol->statement);
|
int64_t offset = statement_offset(statement, symbol->statement);
|
||||||
int64_t absolute = symbol->statement->value.instruction.address;
|
int64_t absolute = ast_node_label_value(symbol->statement)->address;
|
||||||
operand_size_t size = signed_to_size_mask(offset);
|
operand_size_t size = signed_to_size_mask(offset);
|
||||||
|
|
||||||
node->value.reference.address = absolute;
|
node->value.reference.address = absolute;
|
||||||
@ -595,9 +611,38 @@ error_t *encoder_collect_label_info(encoder_t *encoder, ast_node_t *node,
|
|||||||
node->value.reference.size = size;
|
node->value.reference.size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < node->len; ++i) {
|
||||||
|
error_t *err = encoder_collect_reference_info(
|
||||||
|
encoder, node->children[i], statement);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool encoder_should_reencode(ast_node_t *statement) {
|
||||||
|
if (statement->id != NODE_INSTRUCTION)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
instruction_t *instruction = ast_node_instruction_value(statement);
|
||||||
|
return instruction->has_reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_statement_address(ast_node_t *statement, int64_t address) {
|
||||||
|
if (statement->id == NODE_INSTRUCTION) {
|
||||||
|
ast_node_instruction_value(statement)->address = address;
|
||||||
|
} else if (statement->id == NODE_LABEL) {
|
||||||
|
ast_node_label_value(statement)->address = address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t get_statement_length(ast_node_t *statement) {
|
||||||
|
if (statement->id != NODE_INSTRUCTION)
|
||||||
|
return 0;
|
||||||
|
return ast_node_instruction_value(statement)->encoding.len;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform the second pass. Updates the label info and encodes all instructions
|
* Perform the second pass. Updates the label info and encodes all instructions
|
||||||
* that have a label reference.that performs actual encoding.
|
* that have a label reference.that performs actual encoding.
|
||||||
@ -610,28 +655,22 @@ error_t *encoder_second_pass(encoder_t *encoder, bool *did_update) {
|
|||||||
for (size_t i = 0; i < root->len; ++i) {
|
for (size_t i = 0; i < root->len; ++i) {
|
||||||
ast_node_t *statement = root->children[i];
|
ast_node_t *statement = root->children[i];
|
||||||
|
|
||||||
if (statement->id == NODE_INSTRUCTION &&
|
set_statement_address(statement, address);
|
||||||
statement->value.instruction.has_reference) {
|
size_t before = get_statement_length(statement);
|
||||||
statement->value.instruction.address = address;
|
|
||||||
size_t before = statement->value.instruction.encoding.len;
|
if (encoder_should_reencode(statement)) {
|
||||||
error_t *err =
|
error_t *err =
|
||||||
encoder_collect_label_info(encoder, statement, statement);
|
encoder_collect_reference_info(encoder, statement, statement);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
err = encoder_encode_instruction(encoder, statement);
|
err = encoder_encode_instruction(encoder, statement);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
size_t after = statement->value.instruction.encoding.len;
|
|
||||||
address += after;
|
|
||||||
*did_update = *did_update || (before != after);
|
|
||||||
} else if (statement->id == NODE_INSTRUCTION &&
|
|
||||||
statement->value.instruction.has_reference) {
|
|
||||||
statement->value.instruction.address = address;
|
|
||||||
address += statement->value.instruction.encoding.len;
|
|
||||||
} else if (statement->id == NODE_LABEL) {
|
|
||||||
statement->value.label.address = address;
|
|
||||||
}
|
}
|
||||||
address += statement->value.instruction.encoding.len;
|
|
||||||
|
size_t after = get_statement_length(statement);
|
||||||
|
*did_update = *did_update || (before != after);
|
||||||
|
address += after;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user