From bea4c5538e287cd3b5943c1e45e8b24c5b462cb4 Mon Sep 17 00:00:00 2001 From: Oxore Date: Sat, 1 Feb 2025 18:14:31 +0300 Subject: Turn ReferenceRecord chains into a simple linked list --- src/common.h | 1 + src/disasm.cpp | 23 ++++------- src/disasm.h | 13 ++---- src/main.cpp | 122 ++++++++++++++++++++++++++++----------------------------- 4 files changed, 71 insertions(+), 88 deletions(-) diff --git a/src/common.h b/src/common.h index 7b91847..40be645 100644 --- a/src/common.h +++ b/src/common.h @@ -50,6 +50,7 @@ struct Settings { const char *output_dir_path{}; SplitParams split{}; TargetAssembler target_asm{}; + size_t xrefs_per_line{5}; }; using RefKindMask = unsigned; diff --git a/src/disasm.cpp b/src/disasm.cpp index a7dc07b..35c2351 100644 --- a/src/disasm.cpp +++ b/src/disasm.cpp @@ -11,29 +11,22 @@ void DisasmNode::AddReferencedBy(const uint32_t address_from, const ReferenceType ref_type) { - ReferenceNode *node{}; + ReferenceRecord *node = new ReferenceRecord{nullptr, ref_type, address_from}; + assert(node); if (this->last_ref_by) { - node = this->last_ref_by; + this->last_ref_by->next = node; } else { - node = new ReferenceNode{}; - assert(node); - this->ref_by = this->last_ref_by = node; - } - node->refs[node->refs_count] = ReferenceRecord{ref_type, address_from}; - node->refs_count++; - if (node->refs_count >= kRefsCountPerBuffer) { - ReferenceNode *new_node = new ReferenceNode{}; - assert(new_node); - node->next = new_node; - this->last_ref_by = new_node; + assert(nullptr == this->ref_by); + this->ref_by = node; } + this->last_ref_by = node; } DisasmNode::~DisasmNode() { - ReferenceNode *ref{this->ref_by}; + ReferenceRecord *ref{this->ref_by}; while (ref) { - ReferenceNode *prev = ref; + ReferenceRecord *prev = ref; ref = ref->next; delete prev; } diff --git a/src/disasm.h b/src/disasm.h index 5b1b4b9..2a6a1d0 100644 --- a/src/disasm.h +++ b/src/disasm.h @@ -20,18 +20,11 @@ enum class ReferenceType { }; struct ReferenceRecord { + ReferenceRecord *next{}; ReferenceType type{}; uint32_t address{}; }; -constexpr size_t kRefsCountPerBuffer = 10; - -struct ReferenceNode { - ReferenceNode *next{}; - ReferenceRecord refs[kRefsCountPerBuffer]; - uint32_t refs_count{}; -}; - enum class NodeType { kTracedInstruction, kRefInstruction, @@ -50,8 +43,8 @@ struct DisasmNode { uint32_t ref1_addr{}; /// Address of second argument reference uint32_t ref2_addr{}; - ReferenceNode *ref_by{}; - ReferenceNode *last_ref_by{}; + ReferenceRecord *ref_by{}; + ReferenceRecord *last_ref_by{}; Op op{}; /*! Disassembles instruction with arguments diff --git a/src/main.cpp b/src/main.cpp index 338b92b..2a060df 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -78,11 +78,9 @@ static constexpr bool ShouldPrintAsRaw(const Op& op) static constexpr bool HasCallReference(const DisasmNode &node) { - for (const ReferenceNode *ref{node.ref_by}; ref; ref = ref->next) { - for (size_t i = 0; i < ref->refs_count; i++) { - if (ref->refs[i].type == ReferenceType::kCall) { - return true; - } + for (const ReferenceRecord *ref{node.ref_by}; ref; ref = ref->next) { + if (ref->type == ReferenceType::kCall) { + return true; } } return false; @@ -99,49 +97,46 @@ static constexpr size_t GetNodeSizeByAddress(const DisasmMap &disasm_map, const static constexpr bool IsLocalLocation(const DisasmMap &disasm_map, const DisasmNode &node) { - for (const ReferenceNode *ref{node.ref_by}; ref; ref = ref->next) { - for (size_t i = 0; i < ref->refs_count; i++) { - // Check symtab, because we may be crossing a symbol - const DisasmNode *ref_node = disasm_map.FindNodeByAddress(ref->refs[i].address); - if (ref_node != nullptr) { - // We won't cross a symbol at the address if the reference is - // backwards ('1b') and we will cross a symbol if the reference - // is forwards ('1f') - that's why we shift the range one - // instruction forward by adding a size to the address and the - // length. - // TODO write tests for it - uint32_t const address = (node.address < ref_node->address) - ? node.address + node.size - : ref_node->address + ref_node->size; - size_t const length = (node.address < ref_node->address) - ? ref_node->address + ref_node->size - (node.address + node.size) - : node.address + node.size - (ref_node->address + ref_node->size); - if (disasm_map.HasSymbolsInRange(address, length)) { - return false; - } - } - const ReferenceRecord &ref_rec = ref->refs[i]; - if (ref_rec.type == ReferenceType::kCall) { - // Locals are definitely not made for calls + for (const ReferenceRecord *ref{node.ref_by}; ref; ref = ref->next) { + // Check symtab, because we may be crossing a symbol + const DisasmNode *ref_node = disasm_map.FindNodeByAddress(ref->address); + if (ref_node != nullptr) { + // We won't cross a symbol at the address if the reference is + // backwards ('1b') and we will cross a symbol if the reference + // is forwards ('1f') - that's why we shift the range one + // instruction forward by adding a size to the address and the + // length. + // TODO write tests for it + uint32_t const address = (node.address < ref_node->address) + ? node.address + node.size + : ref_node->address + ref_node->size; + size_t const length = (node.address < ref_node->address) + ? ref_node->address + ref_node->size - (node.address + node.size) + : node.address + node.size - (ref_node->address + ref_node->size); + if (disasm_map.HasSymbolsInRange(address, length)) { return false; } - const bool forward = ref_rec.address < node.address; - const size_t min_addr = forward ? ref_rec.address : node.address; - const size_t start = min_addr + GetNodeSizeByAddress(disasm_map, min_addr); - const size_t max_addr = forward ? node.address : ref_rec.address; - const size_t end = max_addr + (forward ? 0 : GetNodeSizeByAddress(disasm_map, min_addr)); - for (size_t addr = start; addr < end;) { - const auto *intermediate_node = disasm_map.FindNodeByAddress(addr); - if (intermediate_node) { - if (intermediate_node->ref_by) { - // Another labeled node detected on the jump path, hence - // current node's location cannot be considered local - return false; - } - addr += intermediate_node->size; - } else { - addr += kInstructionSizeStepBytes; + } + if (ref->type == ReferenceType::kCall) { + // Locals are definitely not made for calls + return false; + } + const bool forward = ref->address < node.address; + const size_t min_addr = forward ? ref->address : node.address; + const size_t start = min_addr + GetNodeSizeByAddress(disasm_map, min_addr); + const size_t max_addr = forward ? node.address : ref->address; + const size_t end = max_addr + (forward ? 0 : GetNodeSizeByAddress(disasm_map, min_addr)); + for (size_t addr = start; addr < end;) { + const auto *intermediate_node = disasm_map.FindNodeByAddress(addr); + if (intermediate_node) { + if (intermediate_node->ref_by) { + // Another labeled node detected on the jump path, hence + // current node's location cannot be considered local + return false; } + addr += intermediate_node->size; + } else { + addr += kInstructionSizeStepBytes; } } } @@ -329,6 +324,11 @@ struct EmitContext { size_t last_rendered_function_symbol_addr{SIZE_MAX}; }; +static constexpr const char *commentSequence(const Settings &s) +{ + return s.target_asm == TargetAssembler::kGnuAs ? "|" : ";"; +} + static bool EmitNodeDisassembly( const EmitContext &ctx, const DisasmMap &disasm_map, @@ -363,8 +363,7 @@ static bool EmitNodeDisassembly( if (s.labels && !is_local) { const bool export_this_function = s.export_functions && have_call_reference; const bool export_this_label = s.export_all_labels || - (s.export_labels && node.ref_by && (node.ref_by->refs_count > 1)) || - export_this_function; + (s.export_labels && node.ref_by) || export_this_function; if (export_this_label) { fprintf(output, "\n%s.globl\t%s\n", s.indent, name); if (export_this_function) { @@ -382,24 +381,21 @@ static bool EmitNodeDisassembly( } } while (0); if (s.xrefs_from && (have_symbol || !is_local)) { - if (s.target_asm == TargetAssembler::kGnuAs) { - fprintf(output, "| XREFS:\n"); - } else { - fprintf(output, "; XREFS:\n"); - } - for (const ReferenceNode *ref{node.ref_by}; ref; ref = ref->next) { - if (ref->refs_count == 0) { - continue; + assert(s.xrefs_per_line >= 1); + fprintf(output, "%s XREFS:\n", commentSequence(s)); + size_t refs_count = 0; + for (const ReferenceRecord *ref{node.ref_by}; ref; ref = ref->next) { + if (refs_count == 0) { + fprintf(output, commentSequence(s)); } - if (s.target_asm == TargetAssembler::kGnuAs) { - fprintf(output, "|"); - } else { - fprintf(output, ";"); - } - for (size_t i = 0; i < ref->refs_count; i++) { - const ReferenceRecord r = ref->refs[i]; - fprintf(output, " %s @%08x", ReferenceTypeToString(r.type), r.address); + fprintf(output, " %s @%08x", ReferenceTypeToString(ref->type), ref->address); + refs_count++; + if (refs_count >= s.xrefs_per_line) { + fprintf(output, "\n"); + refs_count = 0; } + } + if (refs_count != 0) { fprintf(output, "\n"); } } -- cgit v1.2.3