| ... | ... | @@ -181,6 +181,27 @@ const RelocContext = struct { |
| 181 | 181 | base_offset: i32 = 0, |
| 182 | 182 | }; |
| 183 | 183 | |
| 184 | pub fn getRelocContext(zld: *Zld, atom_index: AtomIndex) RelocContext { |
| 185 | const atom = zld.getAtom(atom_index); |
| 186 | assert(atom.getFile() != null); // synthetic atoms do not have relocs |
| 187 | |
| 188 | const object = zld.objects.items[atom.getFile().?]; |
| 189 | if (object.getSourceSymbol(atom.sym_index)) |source_sym| { |
| 190 | const source_sect = object.getSourceSection(source_sym.n_sect - 1); |
| 191 | return .{ |
| 192 | .base_addr = source_sect.addr, |
| 193 | .base_offset = @intCast(i32, source_sym.n_value - source_sect.addr), |
| 194 | }; |
| 195 | } |
| 196 | const nbase = @intCast(u32, object.in_symtab.?.len); |
| 197 | const sect_id = @intCast(u16, atom.sym_index - nbase); |
| 198 | const source_sect = object.getSourceSection(sect_id); |
| 199 | return .{ |
| 200 | .base_addr = source_sect.addr, |
| 201 | .base_offset = 0, |
| 202 | }; |
| 203 | } |
| 204 | |
| 184 | 205 | pub fn parseRelocTarget( |
| 185 | 206 | zld: *Zld, |
| 186 | 207 | atom_index: AtomIndex, |
| ... | ... | @@ -192,6 +213,52 @@ pub fn parseRelocTarget( |
| 192 | 213 | |
| 193 | 214 | if (rel.r_extern == 0) { |
| 194 | 215 | const sect_id = @intCast(u8, rel.r_symbolnum - 1); |
| 216 | const ctx = getRelocContext(zld, atom_index); |
| 217 | const atom_code = getAtomCode(zld, atom_index); |
| 218 | const rel_offset = @intCast(u32, rel.r_address - ctx.base_offset); |
| 219 | |
| 220 | const address_in_section = if (rel.r_pcrel == 0) blk: { |
| 221 | break :blk if (rel.r_length == 3) |
| 222 | mem.readIntLittle(i64, atom_code[rel_offset..][0..8]) |
| 223 | else |
| 224 | mem.readIntLittle(i32, atom_code[rel_offset..][0..4]); |
| 225 | } else blk: { |
| 226 | const correction: u3 = switch (@intToEnum(macho.reloc_type_x86_64, rel.r_type)) { |
| 227 | .X86_64_RELOC_SIGNED => 0, |
| 228 | .X86_64_RELOC_SIGNED_1 => 1, |
| 229 | .X86_64_RELOC_SIGNED_2 => 2, |
| 230 | .X86_64_RELOC_SIGNED_4 => 4, |
| 231 | else => unreachable, |
| 232 | }; |
| 233 | const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]); |
| 234 | const target_address = @intCast(i64, ctx.base_addr) + rel.r_address + 4 + correction + addend; |
| 235 | break :blk target_address; |
| 236 | }; |
| 237 | |
| 238 | // Find containing atom |
| 239 | const Predicate = struct { |
| 240 | addr: i64, |
| 241 | |
| 242 | pub fn predicate(pred: @This(), other: i64) bool { |
| 243 | return if (other == -1) true else other > pred.addr; |
| 244 | } |
| 245 | }; |
| 246 | |
| 247 | if (object.source_section_index_lookup[sect_id] > -1) { |
| 248 | const first_sym_index = @intCast(usize, object.source_section_index_lookup[sect_id]); |
| 249 | const target_sym_index = @import("zld.zig").lsearch(i64, object.source_address_lookup[first_sym_index..], Predicate{ |
| 250 | .addr = address_in_section, |
| 251 | }); |
| 252 | |
| 253 | if (target_sym_index > 0) { |
| 254 | return SymbolWithLoc{ |
| 255 | .sym_index = @intCast(u32, first_sym_index + target_sym_index - 1), |
| 256 | .file = atom.file, |
| 257 | }; |
| 258 | } |
| 259 | } |
| 260 | |
| 261 | // Start of section is not contained anywhere, return synthetic atom. |
| 195 | 262 | const sym_index = object.getSectionAliasSymbolIndex(sect_id); |
| 196 | 263 | return SymbolWithLoc{ .sym_index = sym_index, .file = atom.file }; |
| 197 | 264 | } |
| ... | ... | @@ -405,29 +472,13 @@ pub fn resolveRelocs( |
| 405 | 472 | const atom = zld.getAtom(atom_index); |
| 406 | 473 | assert(atom.getFile() != null); // synthetic atoms do not have relocs |
| 407 | 474 | |
| 408 | | const object = zld.objects.items[atom.getFile().?]; |
| 409 | | const ctx: RelocContext = blk: { |
| 410 | | if (object.getSourceSymbol(atom.sym_index)) |source_sym| { |
| 411 | | const source_sect = object.getSourceSection(source_sym.n_sect - 1); |
| 412 | | break :blk .{ |
| 413 | | .base_addr = source_sect.addr, |
| 414 | | .base_offset = @intCast(i32, source_sym.n_value - source_sect.addr), |
| 415 | | }; |
| 416 | | } |
| 417 | | const nbase = @intCast(u32, object.in_symtab.?.len); |
| 418 | | const sect_id = @intCast(u16, atom.sym_index - nbase); |
| 419 | | const source_sect = object.getSourceSection(sect_id); |
| 420 | | break :blk .{ |
| 421 | | .base_addr = source_sect.addr, |
| 422 | | .base_offset = 0, |
| 423 | | }; |
| 424 | | }; |
| 425 | | |
| 426 | 475 | log.debug("resolving relocations in ATOM(%{d}, '{s}')", .{ |
| 427 | 476 | atom.sym_index, |
| 428 | 477 | zld.getSymbolName(atom.getSymbolWithLoc()), |
| 429 | 478 | }); |
| 430 | 479 | |
| 480 | const ctx = getRelocContext(zld, atom_index); |
| 481 | |
| 431 | 482 | return switch (arch) { |
| 432 | 483 | .aarch64 => resolveRelocsArm64(zld, atom_index, atom_code, atom_relocs, reverse_lookup, ctx), |
| 433 | 484 | .x86_64 => resolveRelocsX86(zld, atom_index, atom_code, atom_relocs, reverse_lookup, ctx), |
| ... | ... | @@ -744,8 +795,11 @@ fn resolveRelocsArm64( |
| 744 | 795 | mem.readIntLittle(i32, atom_code[rel_offset..][0..4]); |
| 745 | 796 | |
| 746 | 797 | if (rel.r_extern == 0) { |
| 747 | | const target_sect_base_addr = object.getSourceSection(@intCast(u16, rel.r_symbolnum - 1)).addr; |
| 748 | | ptr_addend -= @intCast(i64, target_sect_base_addr); |
| 798 | const base_addr = if (target.sym_index > object.source_address_lookup.len) |
| 799 | @intCast(i64, object.getSourceSection(@intCast(u16, rel.r_symbolnum - 1)).addr) |
| 800 | else |
| 801 | object.source_address_lookup[target.sym_index]; |
| 802 | ptr_addend -= base_addr; |
| 749 | 803 | } |
| 750 | 804 | |
| 751 | 805 | const result = blk: { |
| ... | ... | @@ -878,13 +932,12 @@ fn resolveRelocsX86( |
| 878 | 932 | var addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]) + correction; |
| 879 | 933 | |
| 880 | 934 | if (rel.r_extern == 0) { |
| 881 | | // Note for the future self: when r_extern == 0, we should subtract correction from the |
| 882 | | // addend. |
| 883 | | const target_sect_base_addr = object.getSourceSection(@intCast(u16, rel.r_symbolnum - 1)).addr; |
| 884 | | // We need to add base_offset, i.e., offset of this atom wrt to the source |
| 885 | | // section. Otherwise, the addend will over-/under-shoot. |
| 886 | | addend += @intCast(i32, @intCast(i64, context.base_addr + rel_offset + 4) - |
| 887 | | @intCast(i64, target_sect_base_addr) + context.base_offset); |
| 935 | const base_addr = if (target.sym_index > object.source_address_lookup.len) |
| 936 | @intCast(i64, object.getSourceSection(@intCast(u16, rel.r_symbolnum - 1)).addr) |
| 937 | else |
| 938 | object.source_address_lookup[target.sym_index]; |
| 939 | addend += @intCast(i32, @intCast(i64, context.base_addr) + rel.r_address + 4 - |
| 940 | @intCast(i64, base_addr)); |
| 888 | 941 | } |
| 889 | 942 | |
| 890 | 943 | const adjusted_target_addr = @intCast(u64, @intCast(i64, target_addr) + addend); |
| ... | ... | @@ -902,8 +955,11 @@ fn resolveRelocsX86( |
| 902 | 955 | mem.readIntLittle(i32, atom_code[rel_offset..][0..4]); |
| 903 | 956 | |
| 904 | 957 | if (rel.r_extern == 0) { |
| 905 | | const target_sect_base_addr = object.getSourceSection(@intCast(u16, rel.r_symbolnum - 1)).addr; |
| 906 | | addend -= @intCast(i64, target_sect_base_addr); |
| 958 | const base_addr = if (target.sym_index > object.source_address_lookup.len) |
| 959 | @intCast(i64, object.getSourceSection(@intCast(u16, rel.r_symbolnum - 1)).addr) |
| 960 | else |
| 961 | object.source_address_lookup[target.sym_index]; |
| 962 | addend -= base_addr; |
| 907 | 963 | } |
| 908 | 964 | |
| 909 | 965 | const result = blk: { |