-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLinker.cpp
More file actions
119 lines (106 loc) · 4.88 KB
/
Copy pathLinker.cpp
File metadata and controls
119 lines (106 loc) · 4.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// ============================================================
// LINKER
// ===========================================================
// Purpose: LINKING PHASE
// Takes one or more "object files" (here the assembled
// instruction list) and:
// • Merges code sections
// • Injects a runtime library stub (print_val, exit)
// • Assigns virtual addresses to all symbols
// • Resolves all label/symbol references
// ============================================================
#include "Assembler.h"
#include "Linker.h"
#include "Loader.h"
#include <iostream>
#include <iomanip>
// LINKER::link() – public entry point
std::vector<AsmInstruction>
Linker::link(const std::vector<ObjectFile>& objects) {
std::cout << " [LINKER] Resolving symbols across "
<< objects.size() << " object file(s)...\n";
addRuntime(); // Inject print_val + exit stubs first
resolveSymbols(objects); // Build symbol address map
mergeInstructions(objects);// Concatenate all code sections
std::cout << " [LINKER] Linking complete. "
<< linked_.size() << " instructions in final binary.\n";
return linked_;
}
// ADDRUNTIME() – inject standard runtime stubs
void Linker::addRuntime() {
// print_val: pseudo-implementation of the print routine
linked_.push_back({"print_val:", "", "", "runtime: print function entry"});
linked_.push_back({"PUSH", "EBP", "", "save base pointer"});
linked_.push_back({"MOV", "EBP","ESP", "set frame pointer"});
linked_.push_back({"MOV", "EBX","EAX", "arg: value to print"});
linked_.push_back({"CALL", "sys_write","", "syscall: write to stdout"});
linked_.push_back({"POP", "EBP","", "restore base pointer"});
linked_.push_back({"RET", "","", "return to caller"});
// Record runtime symbols
symbolMap_["print_val"] = LinkedSymbol{"print_val", 0, "runtime"};
symbolMap_["sys_write"] = LinkedSymbol{"sys_write", 8, "runtime"};
}
// RESOLVESYMBOLS() – assign addresses to all symbols
void Linker::resolveSymbols(const std::vector<ObjectFile>& objects) {
int addr = (int)linked_.size(); // Start after runtime stubs
for (const auto& obj : objects) {
std::cout << " [LINKER] Processing " << obj.name << "\n";
for (const auto& instr : obj.instructions) {
// A label definition (ends with ':') is a symbol
if (!instr.opcode.empty() && instr.opcode.back() == ':') {
std::string sym = instr.opcode.substr(0, instr.opcode.size() - 1);
symbolMap_[sym] = LinkedSymbol{sym, addr, obj.name};
std::cout << " [LINKER] Symbol '" << sym
<< "' -> address 0x" << std::hex << addr << std::dec << "\n";
}
addr++;
}
// Report unresolved imports
for (const auto& imp : obj.imports) {
if (!symbolMap_.count(imp)) {
std::cout << " [LINKER] WARNING: unresolved symbol '" << imp << "'\n";
} else {
std::cout << " [LINKER] Resolved '" << imp
<< "' -> 0x" << std::hex
<< symbolMap_[imp].address << std::dec << "\n";
}
}
}
}
// MERGEINSTRUCTIONS() – append all object code
void Linker::mergeInstructions(const std::vector<ObjectFile>& objects) {
for (const auto& obj : objects) {
for (const auto& instr : obj.instructions) {
linked_.push_back(instr); // Append each instruction
}
}
}
// PRINTLINKEDOUTPUT() – print the final linked output
void Linker::printLinkedOutput() const {
int addr = 0;
for (const auto& instr : linked_) {
bool isLabel = (!instr.opcode.empty() && instr.opcode.back() == ':');
std::cout << " 0x" << std::hex << std::setw(4)
<< std::setfill('0') << addr << std::dec
<< std::setfill(' ') << " "
<< (isLabel ? "" : " ") << instr.toString() << "\n";
addr++;
}
std::cout << "\n";
}
// PRINTSYMBOLMAP() – print the symbol map
void Linker::printSymbolMap() const {
std::cout << "\n +--------------+-----------+--------------+\n";
std::cout << " | Symbol | Address | Object |\n";
std::cout << " +--------------+-----------+--------------+\n";
for (const auto& entry : symbolMap_) {
const std::string& name = entry.first;
const LinkedSymbol& sym = entry.second;
std::cout << " | " << std::setw(12) << std::left << name
<< " | 0x" << std::hex << std::setw(6) << std::setfill('0')
<< sym.address << std::dec << std::setfill(' ')
<< " | " << std::setw(12) << std::left << sym.section
<< " |\n";
}
std::cout << " +--------------+-----------+--------------+\n\n";
}