mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
macho: document more code + add test case
This commit is contained in:
parent
b86d0e488b
commit
7d40aaad2b
@ -1865,19 +1865,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
// If it doesn't, it will get autofreed when we clean up the extern symbol table.
|
||||
const decl_name = try std.fmt.allocPrint(self.bin_file.allocator, "_{s}", .{decl.name});
|
||||
const already_defined = macho_file.extern_lazy_symbols.contains(decl_name);
|
||||
const symbol: u32 = blk: {
|
||||
if (macho_file.extern_lazy_symbols.get(decl_name)) |sym| {
|
||||
self.bin_file.allocator.free(decl_name);
|
||||
break :blk sym.index;
|
||||
} else {
|
||||
const index = @intCast(u32, macho_file.extern_lazy_symbols.items().len);
|
||||
try macho_file.extern_lazy_symbols.putNoClobber(self.bin_file.allocator, decl_name, .{
|
||||
.name = decl_name,
|
||||
.dylib_ordinal = 1, // TODO this is now hardcoded, since we only support libSystem.
|
||||
.index = index,
|
||||
});
|
||||
break :blk index;
|
||||
}
|
||||
const symbol: u32 = if (macho_file.extern_lazy_symbols.getIndex(decl_name)) |index| blk: {
|
||||
self.bin_file.allocator.free(decl_name);
|
||||
break :blk @intCast(u32, index);
|
||||
} else blk: {
|
||||
const index = @intCast(u32, macho_file.extern_lazy_symbols.items().len);
|
||||
try macho_file.extern_lazy_symbols.putNoClobber(self.bin_file.allocator, decl_name, .{
|
||||
.name = decl_name,
|
||||
.dylib_ordinal = 1, // TODO this is now hardcoded, since we only support libSystem.
|
||||
});
|
||||
break :blk index;
|
||||
};
|
||||
try macho_file.stub_fixups.append(self.bin_file.allocator, .{
|
||||
.symbol = symbol,
|
||||
|
||||
@ -159,16 +159,13 @@ last_text_block: ?*TextBlock = null,
|
||||
/// prior to calling `generateSymbol`, and then immediately deallocated
|
||||
/// rather than sitting in the global scope.
|
||||
pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{},
|
||||
|
||||
/// A list of all stub (extern decls) fixups required for this run of the linker.
|
||||
/// Warning, this is currently NOT thread-safe. See the TODO below.
|
||||
/// TODO Move this list inside `updateDecl` where it should be allocated
|
||||
/// prior to calling `generateSymbol`, and then immediately deallocated
|
||||
/// rather than sitting in the global scope.
|
||||
stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{},
|
||||
|
||||
pub const StubFixup = struct {
|
||||
symbol: u32,
|
||||
already_defined: bool,
|
||||
start: usize,
|
||||
len: usize,
|
||||
};
|
||||
|
||||
pub const PieFixup = struct {
|
||||
/// Target address we wanted to address in absolute terms.
|
||||
address: u64,
|
||||
@ -179,6 +176,19 @@ pub const PieFixup = struct {
|
||||
len: usize,
|
||||
};
|
||||
|
||||
pub const StubFixup = struct {
|
||||
/// Id of extern (lazy) symbol.
|
||||
symbol: u32,
|
||||
/// Signals whether the symbol has already been declared before. If so,
|
||||
/// then there is no need to rewrite the stub entry and related.
|
||||
already_defined: bool,
|
||||
/// Where in the byte stream we should perform the fixup.
|
||||
start: usize,
|
||||
/// The length of the byte stream. For x86_64, this will be
|
||||
/// variable. For aarch64, it will be fixed at 4 bytes.
|
||||
len: usize,
|
||||
};
|
||||
|
||||
/// `alloc_num / alloc_den` is the factor of padding when allocating.
|
||||
pub const alloc_num = 4;
|
||||
pub const alloc_den = 3;
|
||||
@ -1030,13 +1040,20 @@ pub fn deinit(self: *MachO) void {
|
||||
if (self.d_sym) |*ds| {
|
||||
ds.deinit(self.base.allocator);
|
||||
}
|
||||
for (self.extern_lazy_symbols.items()) |*entry| {
|
||||
entry.value.deinit(self.base.allocator);
|
||||
}
|
||||
self.extern_lazy_symbols.deinit(self.base.allocator);
|
||||
for (self.extern_nonlazy_symbols.items()) |*entry| {
|
||||
entry.value.deinit(self.base.allocator);
|
||||
}
|
||||
self.extern_nonlazy_symbols.deinit(self.base.allocator);
|
||||
self.pie_fixups.deinit(self.base.allocator);
|
||||
self.stub_fixups.deinit(self.base.allocator);
|
||||
self.text_block_free_list.deinit(self.base.allocator);
|
||||
self.offset_table.deinit(self.base.allocator);
|
||||
self.offset_table_free_list.deinit(self.base.allocator);
|
||||
self.string_table.deinit(self.base.allocator);
|
||||
self.extern_lazy_symbols.deinit(self.base.allocator);
|
||||
self.extern_nonlazy_symbols.deinit(self.base.allocator);
|
||||
self.global_symbols.deinit(self.base.allocator);
|
||||
self.global_symbol_free_list.deinit(self.base.allocator);
|
||||
self.local_symbols.deinit(self.base.allocator);
|
||||
@ -2047,7 +2064,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {
|
||||
try self.extern_nonlazy_symbols.putNoClobber(self.base.allocator, name, .{
|
||||
.name = name,
|
||||
.dylib_ordinal = 1, // TODO this is currently hardcoded.
|
||||
.index = index,
|
||||
.segment = self.data_const_segment_cmd_index.?,
|
||||
.offset = index * @sizeOf(u64),
|
||||
});
|
||||
@ -2582,12 +2598,12 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {
|
||||
}
|
||||
|
||||
fn writeIndirectSymbolTable(self: *MachO) !void {
|
||||
const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
|
||||
const stubs = &text_seg.sections.items[self.stubs_section_index.?];
|
||||
const dc_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
|
||||
const got = &dc_seg.sections.items[self.data_got_section_index.?];
|
||||
const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
|
||||
const la = &data_seg.sections.items[self.la_symbol_ptr_section_index.?];
|
||||
const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
|
||||
const stubs = &text_segment.sections.items[self.stubs_section_index.?];
|
||||
const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
|
||||
const got = &data_const_seg.sections.items[self.data_got_section_index.?];
|
||||
const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
|
||||
const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];
|
||||
const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
|
||||
dysymtab.nindirectsyms = 0;
|
||||
|
||||
@ -2595,8 +2611,8 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
|
||||
var off = dysymtab.indirectsymoff;
|
||||
|
||||
stubs.reserved1 = 0;
|
||||
for (self.extern_lazy_symbols.items()) |entry| {
|
||||
const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.value.index);
|
||||
for (self.extern_lazy_symbols.items()) |_, i| {
|
||||
const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);
|
||||
mem.writeIntLittle(u32, &buf, symtab_idx);
|
||||
try self.base.file.?.pwriteAll(&buf, off);
|
||||
off += @sizeOf(u32);
|
||||
@ -2605,17 +2621,17 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
|
||||
|
||||
const base_id = @intCast(u32, self.extern_lazy_symbols.items().len);
|
||||
got.reserved1 = base_id;
|
||||
for (self.extern_nonlazy_symbols.items()) |entry| {
|
||||
const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.value.index + base_id);
|
||||
for (self.extern_nonlazy_symbols.items()) |_, i| {
|
||||
const symtab_idx = @intCast(u32, dysymtab.iundefsym + i + base_id);
|
||||
mem.writeIntLittle(u32, &buf, symtab_idx);
|
||||
try self.base.file.?.pwriteAll(&buf, off);
|
||||
off += @sizeOf(u32);
|
||||
dysymtab.nindirectsyms += 1;
|
||||
}
|
||||
|
||||
la.reserved1 = got.reserved1 + @intCast(u32, self.extern_nonlazy_symbols.items().len);
|
||||
for (self.extern_lazy_symbols.items()) |entry| {
|
||||
const symtab_idx = @intCast(u32, dysymtab.iundefsym + entry.value.index);
|
||||
la_symbol_ptr.reserved1 = got.reserved1 + @intCast(u32, self.extern_nonlazy_symbols.items().len);
|
||||
for (self.extern_lazy_symbols.items()) |_, i| {
|
||||
const symtab_idx = @intCast(u32, dysymtab.iundefsym + i);
|
||||
mem.writeIntLittle(u32, &buf, symtab_idx);
|
||||
try self.base.file.?.pwriteAll(&buf, off);
|
||||
off += @sizeOf(u32);
|
||||
|
||||
@ -20,13 +20,15 @@ pub const ExternSymbol = struct {
|
||||
/// dylibs.
|
||||
dylib_ordinal: i64 = 0,
|
||||
|
||||
/// Id of the segment where this symbol is defined (will have its address
|
||||
/// resolved).
|
||||
segment: u16 = 0,
|
||||
|
||||
/// Offset relative to the start address of the `segment`.
|
||||
offset: u32 = 0,
|
||||
addend: ?i32 = null,
|
||||
index: u32,
|
||||
|
||||
pub fn deinit(self: *ExternSymbol, allocator: *Allocator) void {
|
||||
if (self.name) |*name| {
|
||||
if (self.name) |name| {
|
||||
allocator.free(name);
|
||||
}
|
||||
}
|
||||
@ -77,12 +79,6 @@ pub fn bindInfoSize(symbols: []*const ExternSymbol) !u64 {
|
||||
|
||||
size += 1;
|
||||
try leb.writeILEB128(writer, symbol.offset);
|
||||
|
||||
if (symbol.addend) |addend| {
|
||||
size += 1;
|
||||
try leb.writeILEB128(writer, addend);
|
||||
}
|
||||
|
||||
size += 2;
|
||||
}
|
||||
|
||||
@ -110,12 +106,6 @@ pub fn writeBindInfo(symbols: []*const ExternSymbol, writer: anytype) !void {
|
||||
|
||||
try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));
|
||||
try leb.writeILEB128(writer, symbol.offset);
|
||||
|
||||
if (symbol.addend) |addend| {
|
||||
try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
|
||||
try leb.writeILEB128(writer, addend);
|
||||
}
|
||||
|
||||
try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
|
||||
try writer.writeByte(macho.BIND_OPCODE_DONE);
|
||||
}
|
||||
@ -129,12 +119,6 @@ pub fn lazyBindInfoSize(symbols: []*const ExternSymbol) !u64 {
|
||||
for (symbols) |symbol| {
|
||||
size += 1;
|
||||
try leb.writeILEB128(writer, symbol.offset);
|
||||
|
||||
if (symbol.addend) |addend| {
|
||||
size += 1;
|
||||
try leb.writeILEB128(writer, addend);
|
||||
}
|
||||
|
||||
size += 1;
|
||||
if (symbol.dylib_ordinal > 15) {
|
||||
try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));
|
||||
@ -156,11 +140,6 @@ pub fn writeLazyBindInfo(symbols: []*const ExternSymbol, writer: anytype) !void
|
||||
try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @truncate(u4, symbol.segment));
|
||||
try leb.writeILEB128(writer, symbol.offset);
|
||||
|
||||
if (symbol.addend) |addend| {
|
||||
try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
|
||||
try leb.writeILEB128(writer, addend);
|
||||
}
|
||||
|
||||
if (symbol.dylib_ordinal > 15) {
|
||||
try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
|
||||
try leb.writeULEB128(writer, @bitCast(u64, symbol.dylib_ordinal));
|
||||
|
||||
@ -199,4 +199,21 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
"",
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
var case = ctx.exe("hello world linked to libc", macos_aarch64);
|
||||
|
||||
// TODO rewrite this test once we handle more int conversions and return args.
|
||||
case.addCompareOutput(
|
||||
\\extern "c" fn write(usize, usize, usize) void;
|
||||
\\extern "c" fn exit(usize) noreturn;
|
||||
\\
|
||||
\\export fn _start() noreturn {
|
||||
\\ write(1, @ptrToInt("Hello, World!\n"), 14);
|
||||
\\ exit(0);
|
||||
\\}
|
||||
,
|
||||
"Hello, World!\n",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user