///|
/// Machine architectures understood by the first linking milestone.
pub(all) enum LinkMachine {
X86_64
AArch64
}
///|
/// Human-readable machine name.
pub fn LinkMachine::name(self : LinkMachine) -> String {
match self {
X86_64 => "x86-64"
AArch64 => "aarch64"
}
}
///|
/// Symbol binding used during cross-object resolution.
pub(all) enum LinkBinding {
Local
Global
Weak
Other(UInt32)
}
///|
/// Human-readable binding name.
pub fn LinkBinding::name(self : LinkBinding) -> String {
match self {
Local => "LOCAL"
Global => "GLOBAL"
Weak => "WEAK"
Other(value) => "binding(\{value})"
}
}
///|
/// Symbol kind used in link maps and diagnostics.
pub(all) enum LinkSymbolType {
NoType
Object
Func
Section
File
Common
Tls
Other(UInt32)
}
///|
/// Human-readable symbol kind.
pub fn LinkSymbolType::name(self : LinkSymbolType) -> String {
match self {
NoType => "NOTYPE"
Object => "OBJECT"
Func => "FUNC"
Section => "SECTION"
File => "FILE"
Common => "COMMON"
Tls => "TLS"
Other(value) => "type(\{value})"
}
}
///|
/// One section in a link input.
pub(all) struct LinkSection {
index : UInt32
name : String
kind : UInt32
flags : UInt64
address : UInt64
size : UInt64
alignment : UInt64
entry_size : UInt64
}
///|
/// Whether a section occupies memory at runtime.
pub fn LinkSection::is_alloc(self : LinkSection) -> Bool {
(self.flags & 0x2UL) != 0UL
}
///|
/// Whether a section contains executable code.
pub fn LinkSection::is_executable(self : LinkSection) -> Bool {
(self.flags & 0x4UL) != 0UL
}
///|
/// One symbol in a link input.
pub(all) struct LinkSymbol {
index : UInt32
name : String
binding : LinkBinding
kind : LinkSymbolType
visibility : UInt32
section_index : UInt32
value : UInt64
size : UInt64
}
///|
/// Whether this symbol has no defining section.
pub fn LinkSymbol::is_undefined(self : LinkSymbol) -> Bool {
self.section_index == 0
}
///|
/// Whether this symbol participates in cross-object name resolution.
pub fn LinkSymbol::is_global_or_weak(self : LinkSymbol) -> Bool {
match self.binding {
Global | Weak => true
Local | Other(_) => false
}
}
///|
/// Whether this symbol is a tentative common definition.
pub fn LinkSymbol::is_common(self : LinkSymbol) -> Bool {
match self.kind {
Common => true
_ => self.section_index == 0xFFF2
}
}
///|
/// Human-readable binding name.
pub fn LinkSymbol::binding_name(self : LinkSymbol) -> String {
self.binding.name()
}
///|
/// Human-readable symbol kind.
pub fn LinkSymbol::kind_name(self : LinkSymbol) -> String {
self.kind.name()
}
///|
/// One relocation in a link input. `symbol_index` is the index in the
/// flattened `LinkInput.symbols` array.
pub(all) struct LinkRelocation {
target_section : UInt32
offset : UInt64
symbol_index : UInt32
kind : UInt32
addend : Int64
has_addend : Bool
}
///|
/// A normalized, linker-facing view of one relocatable object.
pub(all) struct LinkInput {
name : String
machine : LinkMachine
sections : Array[LinkSection]
symbols : Array[LinkSymbol]
relocations : Array[LinkRelocation]
}
///|
/// Return a section by index.
pub fn LinkInput::section(self : LinkInput, index : UInt32) -> LinkSection? {
if index >= self.sections.length().reinterpret_as_uint() {
None
} else {
Some(self.sections[index.reinterpret_as_int()])
}
}
///|
/// Return the first section with the given name.
pub fn LinkInput::section_by_name(
self : LinkInput,
name : String,
) -> LinkSection? {
for section in self.sections {
if section.name == name {
return Some(section)
}
}
None
}
///|
/// Return the first symbol with the given name.
pub fn LinkInput::symbol_by_name(
self : LinkInput,
name : String,
) -> LinkSymbol? {
for symbol in self.symbols {
if symbol.name == name {
return Some(symbol)
}
}
None
}
///|
/// Return relocations that target a section.
pub fn LinkInput::relocations_for(
self : LinkInput,
target_section : UInt32,
) -> Array[LinkRelocation] {
let result : Array[LinkRelocation] = []
for relocation in self.relocations {
if relocation.target_section == target_section {
result.push(relocation)
}
}
result
}
///|
/// A compact input description for logs and early diagnostics.
pub fn LinkInput::summary(self : LinkInput) -> String {
self.name +
": " +
self.machine.name() +
", " +
self.sections.length().to_string() +
" sections, " +
self.symbols.length().to_string() +
" symbols, " +
self.relocations.length().to_string() +
" relocations"
}