zig/src/link/MachO/Symbol.zig

192 lines
4.0 KiB
Zig

const Symbol = @This();
const std = @import("std");
const macho = std.macho;
const mem = std.mem;
const Allocator = mem.Allocator;
const Dylib = @import("Dylib.zig");
const Object = @import("Object.zig");
const Stub = @import("Stub.zig");
pub const Type = enum {
regular,
proxy,
unresolved,
tentative,
};
/// Symbol type.
@"type": Type,
/// Symbol name. Owned slice.
name: []u8,
/// Alias of.
alias: ?*Symbol = null,
/// Index in GOT table for indirection.
got_index: ?u32 = null,
/// Index in stubs table for late binding.
stubs_index: ?u32 = null,
pub const Regular = struct {
base: Symbol,
/// Linkage type.
linkage: Linkage,
/// Symbol address.
address: u64,
/// Section ID where the symbol resides.
section: u8,
/// Whether the symbol is a weak ref.
weak_ref: bool,
/// Object file where to locate this symbol.
file: *Object,
/// Debug stab if defined.
stab: ?struct {
/// Stab kind
kind: enum {
function,
global,
static,
},
/// Size of the stab.
size: u64,
} = null,
/// True if symbol was already committed into the final
/// symbol table.
visited: bool = false,
pub const base_type: Symbol.Type = .regular;
pub const Linkage = enum {
translation_unit,
linkage_unit,
global,
};
pub fn isTemp(regular: *Regular) bool {
if (regular.linkage == .translation_unit) {
return mem.startsWith(u8, regular.base.name, "l") or mem.startsWith(u8, regular.base.name, "L");
}
return false;
}
};
pub const Proxy = struct {
base: Symbol,
bind_info: std.ArrayListUnmanaged(struct {
segment_id: u16,
address: u64,
}) = .{},
/// Dylib or stub where to locate this symbol.
/// null means self-reference.
file: ?union(enum) {
dylib: *Dylib,
stub: *Stub,
} = null,
pub const base_type: Symbol.Type = .proxy;
pub fn dylibOrdinal(proxy: *Proxy) u16 {
const file = proxy.file orelse return 0;
return switch (file) {
.dylib => |dylib| dylib.ordinal.?,
.stub => |stub| stub.ordinal.?,
};
}
};
pub const Unresolved = struct {
base: Symbol,
/// File where this symbol was referenced.
file: *Object,
pub const base_type: Symbol.Type = .unresolved;
};
pub const Tentative = struct {
base: Symbol,
/// Symbol size.
size: u64,
/// Symbol alignment as power of two.
alignment: u16,
/// File where this symbol was referenced.
file: *Object,
pub const base_type: Symbol.Type = .tentative;
};
pub fn deinit(base: *Symbol, allocator: *Allocator) void {
allocator.free(base.name);
}
pub fn cast(base: *Symbol, comptime T: type) ?*T {
if (base.@"type" != T.base_type) {
return null;
}
return @fieldParentPtr(T, "base", base);
}
pub fn getTopmostAlias(base: *Symbol) *Symbol {
if (base.alias) |alias| {
return alias.getTopmostAlias();
}
return base;
}
pub fn isStab(sym: macho.nlist_64) bool {
return (macho.N_STAB & sym.n_type) != 0;
}
pub fn isPext(sym: macho.nlist_64) bool {
return (macho.N_PEXT & sym.n_type) != 0;
}
pub fn isExt(sym: macho.nlist_64) bool {
return (macho.N_EXT & sym.n_type) != 0;
}
pub fn isSect(sym: macho.nlist_64) bool {
const type_ = macho.N_TYPE & sym.n_type;
return type_ == macho.N_SECT;
}
pub fn isUndf(sym: macho.nlist_64) bool {
const type_ = macho.N_TYPE & sym.n_type;
return type_ == macho.N_UNDF;
}
pub fn isIndr(sym: macho.nlist_64) bool {
const type_ = macho.N_TYPE & sym.n_type;
return type_ == macho.N_INDR;
}
pub fn isAbs(sym: macho.nlist_64) bool {
const type_ = macho.N_TYPE & sym.n_type;
return type_ == macho.N_ABS;
}
pub fn isWeakDef(sym: macho.nlist_64) bool {
return (sym.n_desc & macho.N_WEAK_DEF) != 0;
}
pub fn isWeakRef(sym: macho.nlist_64) bool {
return (sym.n_desc & macho.N_WEAK_REF) != 0;
}