| author | |
| committer | |
| log | f519e781c6f952b3646cb646880ab460ad7a6cce |
| tree | d8229fdb5adec0eb2a438f3cb5048d681cfb7fb9 |
| parent | c47ce310716de806b3d95c328a9c2f9735221806 |
which should make managing the logic of parsing and resolving relocs
that much simpler to parse.5 files changed, 288 insertions(+), 278 deletions(-)
CMakeLists.txt+1| ... | ... | @@ -582,6 +582,7 @@ set(ZIG_STAGE2_SOURCES |
| 582 | 582 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Dylib.zig" |
| 583 | 583 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Object.zig" |
| 584 | 584 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Symbol.zig" |
| 585 | "${CMAKE_SOURCE_DIR}/src/link/MachO/TextBlock.zig" | |
| 585 | 586 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Trie.zig" |
| 586 | 587 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Zld.zig" |
| 587 | 588 | "${CMAKE_SOURCE_DIR}/src/link/MachO/bind.zig" |
src/link/MachO/Object.zig+1-1| ... | ... | @@ -16,7 +16,7 @@ const Allocator = mem.Allocator; |
| 16 | 16 | const Arch = std.Target.Cpu.Arch; |
| 17 | 17 | const Relocation = reloc.Relocation; |
| 18 | 18 | const Symbol = @import("Symbol.zig"); |
| 19 | const TextBlock = Zld.TextBlock; | |
| 19 | const TextBlock = @import("TextBlock.zig"); | |
| 20 | 20 | const Zld = @import("Zld.zig"); |
| 21 | 21 | |
| 22 | 22 | usingnamespace @import("commands.zig"); |
src/link/MachO/TextBlock.zig created+284| ... | ... | @@ -0,0 +1,284 @@ |
| 1 | const TextBlock = @This(); | |
| 2 | ||
| 3 | const std = @import("std"); | |
| 4 | const commands = @import("commands.zig"); | |
| 5 | const log = std.log.scoped(.text_block); | |
| 6 | const macho = std.macho; | |
| 7 | const mem = std.mem; | |
| 8 | const reloc = @import("reloc.zig"); | |
| 9 | ||
| 10 | const Allocator = mem.Allocator; | |
| 11 | const Relocation = reloc.Relocation; | |
| 12 | const Zld = @import("Zld.zig"); | |
| 13 | ||
| 14 | allocator: *Allocator, | |
| 15 | local_sym_index: u32, | |
| 16 | stab: ?Stab = null, | |
| 17 | aliases: std.ArrayList(u32), | |
| 18 | references: std.AutoArrayHashMap(u32, void), | |
| 19 | contained: ?[]SymbolAtOffset = null, | |
| 20 | code: []u8, | |
| 21 | relocs: std.ArrayList(Relocation), | |
| 22 | size: u64, | |
| 23 | alignment: u32, | |
| 24 | rebases: std.ArrayList(u64), | |
| 25 | bindings: std.ArrayList(SymbolAtOffset), | |
| 26 | dices: std.ArrayList(macho.data_in_code_entry), | |
| 27 | next: ?*TextBlock = null, | |
| 28 | prev: ?*TextBlock = null, | |
| 29 | ||
| 30 | pub const SymbolAtOffset = struct { | |
| 31 | local_sym_index: u32, | |
| 32 | offset: u64, | |
| 33 | stab: ?Stab = null, | |
| 34 | }; | |
| 35 | ||
| 36 | pub const Stab = union(enum) { | |
| 37 | function: u64, | |
| 38 | static, | |
| 39 | global, | |
| 40 | ||
| 41 | pub fn asNlists(stab: Stab, local_sym_index: u32, zld: *Zld) ![]macho.nlist_64 { | |
| 42 | var nlists = std.ArrayList(macho.nlist_64).init(zld.allocator); | |
| 43 | defer nlists.deinit(); | |
| 44 | ||
| 45 | const sym = zld.locals.items[local_sym_index]; | |
| 46 | const reg = sym.payload.regular; | |
| 47 | ||
| 48 | switch (stab) { | |
| 49 | .function => |size| { | |
| 50 | try nlists.ensureUnusedCapacity(4); | |
| 51 | const section_id = reg.sectionId(zld); | |
| 52 | nlists.appendAssumeCapacity(.{ | |
| 53 | .n_strx = 0, | |
| 54 | .n_type = macho.N_BNSYM, | |
| 55 | .n_sect = section_id, | |
| 56 | .n_desc = 0, | |
| 57 | .n_value = reg.address, | |
| 58 | }); | |
| 59 | nlists.appendAssumeCapacity(.{ | |
| 60 | .n_strx = sym.strx, | |
| 61 | .n_type = macho.N_FUN, | |
| 62 | .n_sect = section_id, | |
| 63 | .n_desc = 0, | |
| 64 | .n_value = reg.address, | |
| 65 | }); | |
| 66 | nlists.appendAssumeCapacity(.{ | |
| 67 | .n_strx = 0, | |
| 68 | .n_type = macho.N_FUN, | |
| 69 | .n_sect = 0, | |
| 70 | .n_desc = 0, | |
| 71 | .n_value = size, | |
| 72 | }); | |
| 73 | nlists.appendAssumeCapacity(.{ | |
| 74 | .n_strx = 0, | |
| 75 | .n_type = macho.N_ENSYM, | |
| 76 | .n_sect = section_id, | |
| 77 | .n_desc = 0, | |
| 78 | .n_value = size, | |
| 79 | }); | |
| 80 | }, | |
| 81 | .global => { | |
| 82 | try nlists.append(.{ | |
| 83 | .n_strx = sym.strx, | |
| 84 | .n_type = macho.N_GSYM, | |
| 85 | .n_sect = 0, | |
| 86 | .n_desc = 0, | |
| 87 | .n_value = 0, | |
| 88 | }); | |
| 89 | }, | |
| 90 | .static => { | |
| 91 | try nlists.append(.{ | |
| 92 | .n_strx = sym.strx, | |
| 93 | .n_type = macho.N_STSYM, | |
| 94 | .n_sect = reg.sectionId(zld), | |
| 95 | .n_desc = 0, | |
| 96 | .n_value = reg.address, | |
| 97 | }); | |
| 98 | }, | |
| 99 | } | |
| 100 | ||
| 101 | return nlists.toOwnedSlice(); | |
| 102 | } | |
| 103 | }; | |
| 104 | ||
| 105 | pub fn init(allocator: *Allocator) TextBlock { | |
| 106 | return .{ | |
| 107 | .allocator = allocator, | |
| 108 | .local_sym_index = undefined, | |
| 109 | .aliases = std.ArrayList(u32).init(allocator), | |
| 110 | .references = std.AutoArrayHashMap(u32, void).init(allocator), | |
| 111 | .code = undefined, | |
| 112 | .relocs = std.ArrayList(Relocation).init(allocator), | |
| 113 | .size = undefined, | |
| 114 | .alignment = undefined, | |
| 115 | .rebases = std.ArrayList(u64).init(allocator), | |
| 116 | .bindings = std.ArrayList(SymbolAtOffset).init(allocator), | |
| 117 | .dices = std.ArrayList(macho.data_in_code_entry).init(allocator), | |
| 118 | }; | |
| 119 | } | |
| 120 | ||
| 121 | pub fn deinit(self: *TextBlock) void { | |
| 122 | self.aliases.deinit(); | |
| 123 | self.references.deinit(); | |
| 124 | if (self.contained) |contained| { | |
| 125 | self.allocator.free(contained); | |
| 126 | } | |
| 127 | self.allocator.free(self.code); | |
| 128 | self.relocs.deinit(); | |
| 129 | self.rebases.deinit(); | |
| 130 | self.bindings.deinit(); | |
| 131 | self.dices.deinit(); | |
| 132 | } | |
| 133 | ||
| 134 | pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void { | |
| 135 | for (self.relocs.items) |rel| { | |
| 136 | log.debug("relocating {}", .{rel}); | |
| 137 | ||
| 138 | const source_addr = blk: { | |
| 139 | const sym = zld.locals.items[self.local_sym_index]; | |
| 140 | break :blk sym.payload.regular.address + rel.offset; | |
| 141 | }; | |
| 142 | const target_addr = blk: { | |
| 143 | const is_via_got = switch (rel.payload) { | |
| 144 | .pointer_to_got => true, | |
| 145 | .page => |page| page.kind == .got, | |
| 146 | .page_off => |page_off| page_off.kind == .got, | |
| 147 | .load => |load| load.kind == .got, | |
| 148 | else => false, | |
| 149 | }; | |
| 150 | ||
| 151 | if (is_via_got) { | |
| 152 | const dc_seg = zld.load_commands.items[zld.data_const_segment_cmd_index.?].Segment; | |
| 153 | const got = dc_seg.sections.items[zld.got_section_index.?]; | |
| 154 | const got_index = rel.target.got_index orelse { | |
| 155 | log.err("expected GOT entry for symbol '{s}'", .{zld.getString(rel.target.strx)}); | |
| 156 | log.err(" this is an internal linker error", .{}); | |
| 157 | return error.FailedToResolveRelocationTarget; | |
| 158 | }; | |
| 159 | break :blk got.addr + got_index * @sizeOf(u64); | |
| 160 | } | |
| 161 | ||
| 162 | switch (rel.target.payload) { | |
| 163 | .regular => |reg| { | |
| 164 | const is_tlv = is_tlv: { | |
| 165 | const sym = zld.locals.items[self.local_sym_index]; | |
| 166 | const seg = zld.load_commands.items[sym.payload.regular.segment_id].Segment; | |
| 167 | const sect = seg.sections.items[sym.payload.regular.section_id]; | |
| 168 | break :is_tlv commands.sectionType(sect) == macho.S_THREAD_LOCAL_VARIABLES; | |
| 169 | }; | |
| 170 | if (is_tlv) { | |
| 171 | // For TLV relocations, the value specified as a relocation is the displacement from the | |
| 172 | // TLV initializer (either value in __thread_data or zero-init in __thread_bss) to the first | |
| 173 | // defined TLV template init section in the following order: | |
| 174 | // * wrt to __thread_data if defined, then | |
| 175 | // * wrt to __thread_bss | |
| 176 | const seg = zld.load_commands.items[zld.data_segment_cmd_index.?].Segment; | |
| 177 | const base_address = inner: { | |
| 178 | if (zld.tlv_data_section_index) |i| { | |
| 179 | break :inner seg.sections.items[i].addr; | |
| 180 | } else if (zld.tlv_bss_section_index) |i| { | |
| 181 | break :inner seg.sections.items[i].addr; | |
| 182 | } else { | |
| 183 | log.err("threadlocal variables present but no initializer sections found", .{}); | |
| 184 | log.err(" __thread_data not found", .{}); | |
| 185 | log.err(" __thread_bss not found", .{}); | |
| 186 | return error.FailedToResolveRelocationTarget; | |
| 187 | } | |
| 188 | }; | |
| 189 | break :blk reg.address - base_address; | |
| 190 | } | |
| 191 | ||
| 192 | break :blk reg.address; | |
| 193 | }, | |
| 194 | .proxy => { | |
| 195 | if (mem.eql(u8, zld.getString(rel.target.strx), "__tlv_bootstrap")) { | |
| 196 | break :blk 0; // Dynamically bound by dyld. | |
| 197 | } | |
| 198 | ||
| 199 | const segment = zld.load_commands.items[zld.text_segment_cmd_index.?].Segment; | |
| 200 | const stubs = segment.sections.items[zld.stubs_section_index.?]; | |
| 201 | const stubs_index = rel.target.stubs_index orelse { | |
| 202 | // TODO verify in TextBlock that the symbol is indeed dynamically bound. | |
| 203 | break :blk 0; // Dynamically bound by dyld. | |
| 204 | }; | |
| 205 | break :blk stubs.addr + stubs_index * stubs.reserved2; | |
| 206 | }, | |
| 207 | else => { | |
| 208 | log.err("failed to resolve symbol '{s}' as a relocation target", .{ | |
| 209 | zld.getString(rel.target.strx), | |
| 210 | }); | |
| 211 | log.err(" this is an internal linker error", .{}); | |
| 212 | return error.FailedToResolveRelocationTarget; | |
| 213 | }, | |
| 214 | } | |
| 215 | }; | |
| 216 | ||
| 217 | log.debug(" | source_addr = 0x{x}", .{source_addr}); | |
| 218 | log.debug(" | target_addr = 0x{x}", .{target_addr}); | |
| 219 | ||
| 220 | try rel.resolve(self, source_addr, target_addr); | |
| 221 | } | |
| 222 | } | |
| 223 | ||
| 224 | pub fn print_this(self: *const TextBlock, zld: *Zld) void { | |
| 225 | log.warn("TextBlock", .{}); | |
| 226 | log.warn(" {}: {}", .{ self.local_sym_index, zld.locals.items[self.local_sym_index] }); | |
| 227 | if (self.stab) |stab| { | |
| 228 | log.warn(" stab: {}", .{stab}); | |
| 229 | } | |
| 230 | if (self.aliases.items.len > 0) { | |
| 231 | log.warn(" aliases:", .{}); | |
| 232 | for (self.aliases.items) |index| { | |
| 233 | log.warn(" {}: {}", .{ index, zld.locals.items[index] }); | |
| 234 | } | |
| 235 | } | |
| 236 | if (self.references.count() > 0) { | |
| 237 | log.warn(" references:", .{}); | |
| 238 | for (self.references.keys()) |index| { | |
| 239 | log.warn(" {}: {}", .{ index, zld.locals.items[index] }); | |
| 240 | } | |
| 241 | } | |
| 242 | if (self.contained) |contained| { | |
| 243 | log.warn(" contained symbols:", .{}); | |
| 244 | for (contained) |sym_at_off| { | |
| 245 | if (sym_at_off.stab) |stab| { | |
| 246 | log.warn(" {}: {}, stab: {}\n", .{ | |
| 247 | sym_at_off.offset, | |
| 248 | zld.locals.items[sym_at_off.local_sym_index], | |
| 249 | stab, | |
| 250 | }); | |
| 251 | } else { | |
| 252 | log.warn(" {}: {}\n", .{ | |
| 253 | sym_at_off.offset, | |
| 254 | zld.locals.items[sym_at_off.local_sym_index], | |
| 255 | }); | |
| 256 | } | |
| 257 | } | |
| 258 | } | |
| 259 | log.warn(" code.len = {}", .{self.code.len}); | |
| 260 | if (self.relocs.items.len > 0) { | |
| 261 | log.warn(" relocations:", .{}); | |
| 262 | for (self.relocs.items) |rel| { | |
| 263 | log.warn(" {}", .{rel}); | |
| 264 | } | |
| 265 | } | |
| 266 | if (self.rebases.items.len > 0) { | |
| 267 | log.warn(" rebases: {any}", .{self.rebases.items}); | |
| 268 | } | |
| 269 | if (self.bindings.items.len > 0) { | |
| 270 | log.warn(" bindings: {any}", .{self.bindings.items}); | |
| 271 | } | |
| 272 | if (self.dices.items.len > 0) { | |
| 273 | log.warn(" dices: {any}", .{self.dices.items}); | |
| 274 | } | |
| 275 | log.warn(" size = {}", .{self.size}); | |
| 276 | log.warn(" align = {}", .{self.alignment}); | |
| 277 | } | |
| 278 | ||
| 279 | pub fn print(self: *const TextBlock, zld: *Zld) void { | |
| 280 | if (self.prev) |prev| { | |
| 281 | prev.print(zld); | |
| 282 | } | |
| 283 | self.print_this(zld); | |
| 284 | } |
src/link/MachO/Zld.zig+1-276| ... | ... | @@ -10,15 +10,14 @@ const macho = std.macho; |
| 10 | 10 | const math = std.math; |
| 11 | 11 | const log = std.log.scoped(.zld); |
| 12 | 12 | const aarch64 = @import("../../codegen/aarch64.zig"); |
| 13 | const reloc = @import("reloc.zig"); | |
| 14 | 13 | |
| 15 | 14 | const Allocator = mem.Allocator; |
| 16 | 15 | const Archive = @import("Archive.zig"); |
| 17 | 16 | const CodeSignature = @import("CodeSignature.zig"); |
| 18 | 17 | const Dylib = @import("Dylib.zig"); |
| 19 | 18 | const Object = @import("Object.zig"); |
| 20 | const Relocation = reloc.Relocation; | |
| 21 | 19 | const Symbol = @import("Symbol.zig"); |
| 20 | const TextBlock = @import("TextBlock.zig"); | |
| 22 | 21 | const Trie = @import("Trie.zig"); |
| 23 | 22 | |
| 24 | 23 | usingnamespace @import("commands.zig"); |
| ... | ... | @@ -123,280 +122,6 @@ pub const Output = struct { |
| 123 | 122 | install_name: ?[]const u8 = null, |
| 124 | 123 | }; |
| 125 | 124 | |
| 126 | pub const TextBlock = struct { | |
| 127 | allocator: *Allocator, | |
| 128 | local_sym_index: u32, | |
| 129 | stab: ?Stab = null, | |
| 130 | aliases: std.ArrayList(u32), | |
| 131 | references: std.AutoArrayHashMap(u32, void), | |
| 132 | contained: ?[]SymbolAtOffset = null, | |
| 133 | code: []u8, | |
| 134 | relocs: std.ArrayList(Relocation), | |
| 135 | size: u64, | |
| 136 | alignment: u32, | |
| 137 | rebases: std.ArrayList(u64), | |
| 138 | bindings: std.ArrayList(SymbolAtOffset), | |
| 139 | dices: std.ArrayList(macho.data_in_code_entry), | |
| 140 | next: ?*TextBlock = null, | |
| 141 | prev: ?*TextBlock = null, | |
| 142 | ||
| 143 | pub const SymbolAtOffset = struct { | |
| 144 | local_sym_index: u32, | |
| 145 | offset: u64, | |
| 146 | stab: ?Stab = null, | |
| 147 | }; | |
| 148 | ||
| 149 | pub const Stab = union(enum) { | |
| 150 | function: u64, | |
| 151 | static, | |
| 152 | global, | |
| 153 | ||
| 154 | pub fn asNlists(stab: Stab, local_sym_index: u32, zld: *Zld) ![]macho.nlist_64 { | |
| 155 | var nlists = std.ArrayList(macho.nlist_64).init(zld.allocator); | |
| 156 | defer nlists.deinit(); | |
| 157 | ||
| 158 | const sym = zld.locals.items[local_sym_index]; | |
| 159 | const reg = sym.payload.regular; | |
| 160 | ||
| 161 | switch (stab) { | |
| 162 | .function => |size| { | |
| 163 | try nlists.ensureUnusedCapacity(4); | |
| 164 | const section_id = reg.sectionId(zld); | |
| 165 | nlists.appendAssumeCapacity(.{ | |
| 166 | .n_strx = 0, | |
| 167 | .n_type = macho.N_BNSYM, | |
| 168 | .n_sect = section_id, | |
| 169 | .n_desc = 0, | |
| 170 | .n_value = reg.address, | |
| 171 | }); | |
| 172 | nlists.appendAssumeCapacity(.{ | |
| 173 | .n_strx = sym.strx, | |
| 174 | .n_type = macho.N_FUN, | |
| 175 | .n_sect = section_id, | |
| 176 | .n_desc = 0, | |
| 177 | .n_value = reg.address, | |
| 178 | }); | |
| 179 | nlists.appendAssumeCapacity(.{ | |
| 180 | .n_strx = 0, | |
| 181 | .n_type = macho.N_FUN, | |
| 182 | .n_sect = 0, | |
| 183 | .n_desc = 0, | |
| 184 | .n_value = size, | |
| 185 | }); | |
| 186 | nlists.appendAssumeCapacity(.{ | |
| 187 | .n_strx = 0, | |
| 188 | .n_type = macho.N_ENSYM, | |
| 189 | .n_sect = section_id, | |
| 190 | .n_desc = 0, | |
| 191 | .n_value = size, | |
| 192 | }); | |
| 193 | }, | |
| 194 | .global => { | |
| 195 | try nlists.append(.{ | |
| 196 | .n_strx = sym.strx, | |
| 197 | .n_type = macho.N_GSYM, | |
| 198 | .n_sect = 0, | |
| 199 | .n_desc = 0, | |
| 200 | .n_value = 0, | |
| 201 | }); | |
| 202 | }, | |
| 203 | .static => { | |
| 204 | try nlists.append(.{ | |
| 205 | .n_strx = sym.strx, | |
| 206 | .n_type = macho.N_STSYM, | |
| 207 | .n_sect = reg.sectionId(zld), | |
| 208 | .n_desc = 0, | |
| 209 | .n_value = reg.address, | |
| 210 | }); | |
| 211 | }, | |
| 212 | } | |
| 213 | ||
| 214 | return nlists.toOwnedSlice(); | |
| 215 | } | |
| 216 | }; | |
| 217 | ||
| 218 | pub fn init(allocator: *Allocator) TextBlock { | |
| 219 | return .{ | |
| 220 | .allocator = allocator, | |
| 221 | .local_sym_index = undefined, | |
| 222 | .aliases = std.ArrayList(u32).init(allocator), | |
| 223 | .references = std.AutoArrayHashMap(u32, void).init(allocator), | |
| 224 | .code = undefined, | |
| 225 | .relocs = std.ArrayList(Relocation).init(allocator), | |
| 226 | .size = undefined, | |
| 227 | .alignment = undefined, | |
| 228 | .rebases = std.ArrayList(u64).init(allocator), | |
| 229 | .bindings = std.ArrayList(SymbolAtOffset).init(allocator), | |
| 230 | .dices = std.ArrayList(macho.data_in_code_entry).init(allocator), | |
| 231 | }; | |
| 232 | } | |
| 233 | ||
| 234 | pub fn deinit(self: *TextBlock) void { | |
| 235 | self.aliases.deinit(); | |
| 236 | self.references.deinit(); | |
| 237 | if (self.contained) |contained| { | |
| 238 | self.allocator.free(contained); | |
| 239 | } | |
| 240 | self.allocator.free(self.code); | |
| 241 | self.relocs.deinit(); | |
| 242 | self.rebases.deinit(); | |
| 243 | self.bindings.deinit(); | |
| 244 | self.dices.deinit(); | |
| 245 | } | |
| 246 | ||
| 247 | pub fn resolveRelocs(self: *TextBlock, zld: *Zld) !void { | |
| 248 | for (self.relocs.items) |rel| { | |
| 249 | log.debug("relocating {}", .{rel}); | |
| 250 | ||
| 251 | const source_addr = blk: { | |
| 252 | const sym = zld.locals.items[self.local_sym_index]; | |
| 253 | break :blk sym.payload.regular.address + rel.offset; | |
| 254 | }; | |
| 255 | const target_addr = blk: { | |
| 256 | const is_via_got = switch (rel.payload) { | |
| 257 | .pointer_to_got => true, | |
| 258 | .page => |page| page.kind == .got, | |
| 259 | .page_off => |page_off| page_off.kind == .got, | |
| 260 | .load => |load| load.kind == .got, | |
| 261 | else => false, | |
| 262 | }; | |
| 263 | ||
| 264 | if (is_via_got) { | |
| 265 | const dc_seg = zld.load_commands.items[zld.data_const_segment_cmd_index.?].Segment; | |
| 266 | const got = dc_seg.sections.items[zld.got_section_index.?]; | |
| 267 | const got_index = rel.target.got_index orelse { | |
| 268 | log.err("expected GOT entry for symbol '{s}'", .{zld.getString(rel.target.strx)}); | |
| 269 | log.err(" this is an internal linker error", .{}); | |
| 270 | return error.FailedToResolveRelocationTarget; | |
| 271 | }; | |
| 272 | break :blk got.addr + got_index * @sizeOf(u64); | |
| 273 | } | |
| 274 | ||
| 275 | switch (rel.target.payload) { | |
| 276 | .regular => |reg| { | |
| 277 | const is_tlv = is_tlv: { | |
| 278 | const sym = zld.locals.items[self.local_sym_index]; | |
| 279 | const seg = zld.load_commands.items[sym.payload.regular.segment_id].Segment; | |
| 280 | const sect = seg.sections.items[sym.payload.regular.section_id]; | |
| 281 | break :is_tlv sectionType(sect) == macho.S_THREAD_LOCAL_VARIABLES; | |
| 282 | }; | |
| 283 | if (is_tlv) { | |
| 284 | // For TLV relocations, the value specified as a relocation is the displacement from the | |
| 285 | // TLV initializer (either value in __thread_data or zero-init in __thread_bss) to the first | |
| 286 | // defined TLV template init section in the following order: | |
| 287 | // * wrt to __thread_data if defined, then | |
| 288 | // * wrt to __thread_bss | |
| 289 | const seg = zld.load_commands.items[zld.data_segment_cmd_index.?].Segment; | |
| 290 | const base_address = inner: { | |
| 291 | if (zld.tlv_data_section_index) |i| { | |
| 292 | break :inner seg.sections.items[i].addr; | |
| 293 | } else if (zld.tlv_bss_section_index) |i| { | |
| 294 | break :inner seg.sections.items[i].addr; | |
| 295 | } else { | |
| 296 | log.err("threadlocal variables present but no initializer sections found", .{}); | |
| 297 | log.err(" __thread_data not found", .{}); | |
| 298 | log.err(" __thread_bss not found", .{}); | |
| 299 | return error.FailedToResolveRelocationTarget; | |
| 300 | } | |
| 301 | }; | |
| 302 | break :blk reg.address - base_address; | |
| 303 | } | |
| 304 | ||
| 305 | break :blk reg.address; | |
| 306 | }, | |
| 307 | .proxy => { | |
| 308 | if (mem.eql(u8, zld.getString(rel.target.strx), "__tlv_bootstrap")) { | |
| 309 | break :blk 0; // Dynamically bound by dyld. | |
| 310 | } | |
| 311 | ||
| 312 | const segment = zld.load_commands.items[zld.text_segment_cmd_index.?].Segment; | |
| 313 | const stubs = segment.sections.items[zld.stubs_section_index.?]; | |
| 314 | const stubs_index = rel.target.stubs_index orelse { | |
| 315 | // TODO verify in TextBlock that the symbol is indeed dynamically bound. | |
| 316 | break :blk 0; // Dynamically bound by dyld. | |
| 317 | }; | |
| 318 | break :blk stubs.addr + stubs_index * stubs.reserved2; | |
| 319 | }, | |
| 320 | else => { | |
| 321 | log.err("failed to resolve symbol '{s}' as a relocation target", .{ | |
| 322 | zld.getString(rel.target.strx), | |
| 323 | }); | |
| 324 | log.err(" this is an internal linker error", .{}); | |
| 325 | return error.FailedToResolveRelocationTarget; | |
| 326 | }, | |
| 327 | } | |
| 328 | }; | |
| 329 | ||
| 330 | log.debug(" | source_addr = 0x{x}", .{source_addr}); | |
| 331 | log.debug(" | target_addr = 0x{x}", .{target_addr}); | |
| 332 | ||
| 333 | try rel.resolve(self, source_addr, target_addr); | |
| 334 | } | |
| 335 | } | |
| 336 | ||
| 337 | pub fn print_this(self: *const TextBlock, zld: *Zld) void { | |
| 338 | log.warn("TextBlock", .{}); | |
| 339 | log.warn(" {}: {}", .{ self.local_sym_index, zld.locals.items[self.local_sym_index] }); | |
| 340 | if (self.stab) |stab| { | |
| 341 | log.warn(" stab: {}", .{stab}); | |
| 342 | } | |
| 343 | if (self.aliases.items.len > 0) { | |
| 344 | log.warn(" aliases:", .{}); | |
| 345 | for (self.aliases.items) |index| { | |
| 346 | log.warn(" {}: {}", .{ index, zld.locals.items[index] }); | |
| 347 | } | |
| 348 | } | |
| 349 | if (self.references.count() > 0) { | |
| 350 | log.warn(" references:", .{}); | |
| 351 | for (self.references.keys()) |index| { | |
| 352 | log.warn(" {}: {}", .{ index, zld.locals.items[index] }); | |
| 353 | } | |
| 354 | } | |
| 355 | if (self.contained) |contained| { | |
| 356 | log.warn(" contained symbols:", .{}); | |
| 357 | for (contained) |sym_at_off| { | |
| 358 | if (sym_at_off.stab) |stab| { | |
| 359 | log.warn(" {}: {}, stab: {}\n", .{ | |
| 360 | sym_at_off.offset, | |
| 361 | zld.locals.items[sym_at_off.local_sym_index], | |
| 362 | stab, | |
| 363 | }); | |
| 364 | } else { | |
| 365 | log.warn(" {}: {}\n", .{ | |
| 366 | sym_at_off.offset, | |
| 367 | zld.locals.items[sym_at_off.local_sym_index], | |
| 368 | }); | |
| 369 | } | |
| 370 | } | |
| 371 | } | |
| 372 | log.warn(" code.len = {}", .{self.code.len}); | |
| 373 | if (self.relocs.items.len > 0) { | |
| 374 | log.warn(" relocations:", .{}); | |
| 375 | for (self.relocs.items) |rel| { | |
| 376 | log.warn(" {}", .{rel}); | |
| 377 | } | |
| 378 | } | |
| 379 | if (self.rebases.items.len > 0) { | |
| 380 | log.warn(" rebases: {any}", .{self.rebases.items}); | |
| 381 | } | |
| 382 | if (self.bindings.items.len > 0) { | |
| 383 | log.warn(" bindings: {any}", .{self.bindings.items}); | |
| 384 | } | |
| 385 | if (self.dices.items.len > 0) { | |
| 386 | log.warn(" dices: {any}", .{self.dices.items}); | |
| 387 | } | |
| 388 | log.warn(" size = {}", .{self.size}); | |
| 389 | log.warn(" align = {}", .{self.alignment}); | |
| 390 | } | |
| 391 | ||
| 392 | pub fn print(self: *const TextBlock, zld: *Zld) void { | |
| 393 | if (self.prev) |prev| { | |
| 394 | prev.print(zld); | |
| 395 | } | |
| 396 | self.print_this(zld); | |
| 397 | } | |
| 398 | }; | |
| 399 | ||
| 400 | 125 | /// Default path to dyld |
| 401 | 126 | const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld"; |
| 402 | 127 |
src/link/MachO/reloc.zig+1-1| ... | ... | @@ -12,7 +12,7 @@ const Allocator = mem.Allocator; |
| 12 | 12 | const Arch = std.Target.Cpu.Arch; |
| 13 | 13 | const Object = @import("Object.zig"); |
| 14 | 14 | const Symbol = @import("Symbol.zig"); |
| 15 | const TextBlock = Zld.TextBlock; | |
| 15 | const TextBlock = @import("TextBlock.zig"); | |
| 16 | 16 | const Zld = @import("Zld.zig"); |
| 17 | 17 | |
| 18 | 18 | pub const Relocation = struct { |