| author | |
| committer | |
| log | 15b85df3dd8a754bc26159ea2202781b748a613e |
| tree | 0d39fefe78b408358a1f9ac223126b7887debf4a |
| parent | 54888c6f4699b07eadd21b744d797006fb96a284 |
5 files changed, 672 insertions(+), 632 deletions(-)
src/link/MachO/Object.zig+106-16| ... | @@ -53,6 +53,7 @@ initializers: std.ArrayListUnmanaged(u32) = .{}, | ... | @@ -53,6 +53,7 @@ initializers: std.ArrayListUnmanaged(u32) = .{}, |
| 53 | data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{}, | 53 | data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{}, |
| 54 | 54 | ||
| 55 | symbols: std.ArrayListUnmanaged(*Symbol) = .{}, | 55 | symbols: std.ArrayListUnmanaged(*Symbol) = .{}, |
| 56 | sections_as_symbols: std.AutoHashMapUnmanaged(u8, *Symbol) = .{}, | ||
| 56 | 57 | ||
| 57 | const DebugInfo = struct { | 58 | const DebugInfo = struct { |
| 58 | inner: dwarf.DwarfInfo, | 59 | inner: dwarf.DwarfInfo, |
| ... | @@ -160,6 +161,7 @@ pub fn deinit(self: *Object) void { | ... | @@ -160,6 +161,7 @@ pub fn deinit(self: *Object) void { |
| 160 | self.symtab.deinit(self.allocator); | 161 | self.symtab.deinit(self.allocator); |
| 161 | self.strtab.deinit(self.allocator); | 162 | self.strtab.deinit(self.allocator); |
| 162 | self.symbols.deinit(self.allocator); | 163 | self.symbols.deinit(self.allocator); |
| 164 | self.sections_as_symbols.deinit(self.allocator); | ||
| 163 | 165 | ||
| 164 | if (self.name) |n| { | 166 | if (self.name) |n| { |
| 165 | self.allocator.free(n); | 167 | self.allocator.free(n); |
| ... | @@ -312,7 +314,7 @@ fn filterRelocs(relocs: []macho.relocation_info, start: u64, end: u64) []macho.r | ... | @@ -312,7 +314,7 @@ fn filterRelocs(relocs: []macho.relocation_info, start: u64, end: u64) []macho.r |
| 312 | 314 | ||
| 313 | while (true) { | 315 | while (true) { |
| 314 | var change = false; | 316 | var change = false; |
| 315 | if (relocs[start_id].r_address > end) { | 317 | if (relocs[start_id].r_address >= end) { |
| 316 | start_id += 1; | 318 | start_id += 1; |
| 317 | change = true; | 319 | change = true; |
| 318 | } | 320 | } |
| ... | @@ -332,6 +334,7 @@ const TextBlockParser = struct { | ... | @@ -332,6 +334,7 @@ const TextBlockParser = struct { |
| 332 | allocator: *Allocator, | 334 | allocator: *Allocator, |
| 333 | section: macho.section_64, | 335 | section: macho.section_64, |
| 334 | code: []u8, | 336 | code: []u8, |
| 337 | relocs: []macho.relocation_info, | ||
| 335 | object: *Object, | 338 | object: *Object, |
| 336 | zld: *Zld, | 339 | zld: *Zld, |
| 337 | nlists: []NlistWithIndex, | 340 | nlists: []NlistWithIndex, |
| ... | @@ -405,6 +408,7 @@ const TextBlockParser = struct { | ... | @@ -405,6 +408,7 @@ const TextBlockParser = struct { |
| 405 | 408 | ||
| 406 | const start_addr = senior_nlist.nlist.n_value - self.section.addr; | 409 | const start_addr = senior_nlist.nlist.n_value - self.section.addr; |
| 407 | const end_addr = if (next_nlist) |n| n.nlist.n_value - self.section.addr else self.section.size; | 410 | const end_addr = if (next_nlist) |n| n.nlist.n_value - self.section.addr else self.section.size; |
| 411 | log.warn("{} - {}", .{ start_addr, end_addr }); | ||
| 408 | 412 | ||
| 409 | const code = self.code[start_addr..end_addr]; | 413 | const code = self.code[start_addr..end_addr]; |
| 410 | const size = code.len; | 414 | const size = code.len; |
| ... | @@ -424,11 +428,18 @@ const TextBlockParser = struct { | ... | @@ -424,11 +428,18 @@ const TextBlockParser = struct { |
| 424 | block.* = .{ | 428 | block.* = .{ |
| 425 | .local_sym_index = senior_nlist.index, | 429 | .local_sym_index = senior_nlist.index, |
| 426 | .aliases = alias_only_indices, | 430 | .aliases = alias_only_indices, |
| 427 | .code = code, | 431 | .references = std.AutoArrayHashMap(u32, void).init(self.allocator), |
| 432 | .code = try self.allocator.dupe(u8, code), | ||
| 433 | .relocs = std.ArrayList(*Relocation).init(self.allocator), | ||
| 428 | .size = size, | 434 | .size = size, |
| 429 | .alignment = self.section.@"align", | 435 | .alignment = self.section.@"align", |
| 430 | }; | 436 | }; |
| 431 | 437 | ||
| 438 | const relocs = filterRelocs(self.relocs, start_addr, end_addr); | ||
| 439 | if (relocs.len > 0) { | ||
| 440 | try self.object.parseRelocs(self.zld, relocs, block, start_addr); | ||
| 441 | } | ||
| 442 | |||
| 432 | self.index += 1; | 443 | self.index += 1; |
| 433 | 444 | ||
| 434 | return block; | 445 | return block; |
| ... | @@ -457,7 +468,8 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { | ... | @@ -457,7 +468,8 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 457 | 468 | ||
| 458 | sort.sort(NlistWithIndex, sorted_nlists.items, {}, NlistWithIndex.lessThan); | 469 | sort.sort(NlistWithIndex, sorted_nlists.items, {}, NlistWithIndex.lessThan); |
| 459 | 470 | ||
| 460 | for (seg.sections.items) |sect, sect_id| { | 471 | for (seg.sections.items) |sect, id| { |
| 472 | const sect_id = @intCast(u8, id); | ||
| 461 | log.warn("putting section '{s},{s}' as a TextBlock", .{ | 473 | log.warn("putting section '{s},{s}' as a TextBlock", .{ |
| 462 | segmentName(sect), | 474 | segmentName(sect), |
| 463 | sectionName(sect), | 475 | sectionName(sect), |
| ... | @@ -474,6 +486,12 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { | ... | @@ -474,6 +486,12 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 474 | defer self.allocator.free(code); | 486 | defer self.allocator.free(code); |
| 475 | _ = try self.file.?.preadAll(code, sect.offset); | 487 | _ = try self.file.?.preadAll(code, sect.offset); |
| 476 | 488 | ||
| 489 | // Read section's list of relocations | ||
| 490 | var raw_relocs = try self.allocator.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); | ||
| 491 | defer self.allocator.free(raw_relocs); | ||
| 492 | _ = try self.file.?.preadAll(raw_relocs, sect.reloff); | ||
| 493 | const relocs = mem.bytesAsSlice(macho.relocation_info, raw_relocs); | ||
| 494 | |||
| 477 | // Is there any padding between symbols within the section? | 495 | // Is there any padding between symbols within the section? |
| 478 | const is_padded = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0; | 496 | const is_padded = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0; |
| 479 | 497 | ||
| ... | @@ -481,7 +499,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { | ... | @@ -481,7 +499,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 481 | if (is_padded) blocks: { | 499 | if (is_padded) blocks: { |
| 482 | const filtered_nlists = NlistWithIndex.filterInSection( | 500 | const filtered_nlists = NlistWithIndex.filterInSection( |
| 483 | sorted_nlists.items, | 501 | sorted_nlists.items, |
| 484 | @intCast(u8, sect_id + 1), | 502 | sect_id + 1, |
| 485 | ); | 503 | ); |
| 486 | 504 | ||
| 487 | if (filtered_nlists.len == 0) break :blocks; | 505 | if (filtered_nlists.len == 0) break :blocks; |
| ... | @@ -490,6 +508,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { | ... | @@ -490,6 +508,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 490 | .allocator = self.allocator, | 508 | .allocator = self.allocator, |
| 491 | .section = sect, | 509 | .section = sect, |
| 492 | .code = code, | 510 | .code = code, |
| 511 | .relocs = relocs, | ||
| 493 | .object = self, | 512 | .object = self, |
| 494 | .zld = zld, | 513 | .zld = zld, |
| 495 | .nlists = filtered_nlists, | 514 | .nlists = filtered_nlists, |
| ... | @@ -518,8 +537,6 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { | ... | @@ -518,8 +537,6 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 518 | } | 537 | } |
| 519 | } | 538 | } |
| 520 | 539 | ||
| 521 | // TODO parse relocs | ||
| 522 | |||
| 523 | if (zld.last_text_block) |last| { | 540 | if (zld.last_text_block) |last| { |
| 524 | last.next = block; | 541 | last.next = block; |
| 525 | block.prev = last; | 542 | block.prev = last; |
| ... | @@ -531,14 +548,19 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { | ... | @@ -531,14 +548,19 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 531 | } | 548 | } |
| 532 | 549 | ||
| 533 | // Since there is no symbol to refer to this block, we create | 550 | // Since there is no symbol to refer to this block, we create |
| 534 | // a temp one. | 551 | // a temp one, unless we already did that when working out the relocations |
| 535 | const name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{ | 552 | // of other text blocks. |
| 536 | self.name.?, | 553 | const symbol = self.sections_as_symbols.get(sect_id) orelse symbol: { |
| 537 | segmentName(sect), | 554 | const name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{ |
| 538 | sectionName(sect), | 555 | self.name.?, |
| 539 | }); | 556 | segmentName(sect), |
| 540 | defer self.allocator.free(name); | 557 | sectionName(sect), |
| 541 | const symbol = try Symbol.new(self.allocator, name); | 558 | }); |
| 559 | defer self.allocator.free(name); | ||
| 560 | const symbol = try Symbol.new(self.allocator, name); | ||
| 561 | try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol); | ||
| 562 | break :symbol symbol; | ||
| 563 | }; | ||
| 542 | symbol.payload = .{ | 564 | symbol.payload = .{ |
| 543 | .regular = .{ | 565 | .regular = .{ |
| 544 | .linkage = .translation_unit, | 566 | .linkage = .translation_unit, |
| ... | @@ -555,12 +577,16 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { | ... | @@ -555,12 +577,16 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 555 | 577 | ||
| 556 | block.* = .{ | 578 | block.* = .{ |
| 557 | .local_sym_index = local_sym_index, | 579 | .local_sym_index = local_sym_index, |
| 558 | .code = code, | 580 | .references = std.AutoArrayHashMap(u32, void).init(self.allocator), |
| 581 | .code = try self.allocator.dupe(u8, code), | ||
| 582 | .relocs = std.ArrayList(*Relocation).init(self.allocator), | ||
| 559 | .size = sect.size, | 583 | .size = sect.size, |
| 560 | .alignment = sect.@"align", | 584 | .alignment = sect.@"align", |
| 561 | }; | 585 | }; |
| 562 | 586 | ||
| 563 | // TODO parse relocs | 587 | if (relocs.len > 0) { |
| 588 | try self.parseRelocs(zld, relocs, block, 0); | ||
| 589 | } | ||
| 564 | 590 | ||
| 565 | if (zld.last_text_block) |last| { | 591 | if (zld.last_text_block) |last| { |
| 566 | last.next = block; | 592 | last.next = block; |
| ... | @@ -571,6 +597,70 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { | ... | @@ -571,6 +597,70 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 571 | } | 597 | } |
| 572 | } | 598 | } |
| 573 | 599 | ||
| 600 | fn parseRelocs( | ||
| 601 | self: *Object, | ||
| 602 | zld: *Zld, | ||
| 603 | relocs: []const macho.relocation_info, | ||
| 604 | block: *TextBlock, | ||
| 605 | base_addr: u64, | ||
| 606 | ) !void { | ||
| 607 | var it = reloc.RelocIterator{ | ||
| 608 | .buffer = relocs, | ||
| 609 | }; | ||
| 610 | |||
| 611 | switch (self.arch.?) { | ||
| 612 | .aarch64 => { | ||
| 613 | var parser = reloc.aarch64.Parser{ | ||
| 614 | .object = self, | ||
| 615 | .zld = zld, | ||
| 616 | .it = &it, | ||
| 617 | .block = block, | ||
| 618 | .base_addr = base_addr, | ||
| 619 | }; | ||
| 620 | try parser.parse(); | ||
| 621 | }, | ||
| 622 | .x86_64 => { | ||
| 623 | var parser = reloc.x86_64.Parser{ | ||
| 624 | .object = self, | ||
| 625 | .zld = zld, | ||
| 626 | .it = &it, | ||
| 627 | .block = block, | ||
| 628 | .base_addr = base_addr, | ||
| 629 | }; | ||
| 630 | try parser.parse(); | ||
| 631 | }, | ||
| 632 | else => unreachable, | ||
| 633 | } | ||
| 634 | } | ||
| 635 | |||
| 636 | pub fn symbolFromReloc(self: *Object, rel: macho.relocation_info) !*Symbol { | ||
| 637 | const symbol = blk: { | ||
| 638 | if (rel.r_extern == 1) { | ||
| 639 | break :blk self.symbols.items[rel.r_symbolnum]; | ||
| 640 | } else { | ||
| 641 | const sect_id = @intCast(u8, rel.r_symbolnum - 1); | ||
| 642 | const symbol = self.sections_as_symbols.get(sect_id) orelse symbol: { | ||
| 643 | // We need a valid pointer to Symbol even if there is no symbol, so we create a | ||
| 644 | // dummy symbol upfront which will later be populated when created a TextBlock from | ||
| 645 | // the target section here. | ||
| 646 | const seg = self.load_commands.items[self.segment_cmd_index.?].Segment; | ||
| 647 | const sect = seg.sections.items[sect_id]; | ||
| 648 | const name = try std.fmt.allocPrint(self.allocator, "l_{s}_{s}_{s}", .{ | ||
| 649 | self.name.?, | ||
| 650 | segmentName(sect), | ||
| 651 | sectionName(sect), | ||
| 652 | }); | ||
| 653 | defer self.allocator.free(name); | ||
| 654 | const symbol = try Symbol.new(self.allocator, name); | ||
| 655 | try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol); | ||
| 656 | break :symbol symbol; | ||
| 657 | }; | ||
| 658 | break :blk symbol; | ||
| 659 | } | ||
| 660 | }; | ||
| 661 | return symbol; | ||
| 662 | } | ||
| 663 | |||
| 574 | pub fn parseInitializers(self: *Object) !void { | 664 | pub fn parseInitializers(self: *Object) !void { |
| 575 | const index = self.mod_init_func_section_index orelse return; | 665 | const index = self.mod_init_func_section_index orelse return; |
| 576 | const section = self.sections.items[index]; | 666 | const section = self.sections.items[index]; |
src/link/MachO/Zld.zig+18-62| ... | @@ -135,9 +135,9 @@ const TlvOffset = struct { | ... | @@ -135,9 +135,9 @@ const TlvOffset = struct { |
| 135 | pub const TextBlock = struct { | 135 | pub const TextBlock = struct { |
| 136 | local_sym_index: u32, | 136 | local_sym_index: u32, |
| 137 | aliases: ?[]u32 = null, | 137 | aliases: ?[]u32 = null, |
| 138 | references: ?[]u32 = null, | 138 | references: std.AutoArrayHashMap(u32, void), |
| 139 | code: []u8, | 139 | code: []u8, |
| 140 | relocs: ?[]*Relocation = null, | 140 | relocs: std.ArrayList(*Relocation), |
| 141 | size: u64, | 141 | size: u64, |
| 142 | alignment: u32, | 142 | alignment: u32, |
| 143 | next: ?*TextBlock = null, | 143 | next: ?*TextBlock = null, |
| ... | @@ -147,15 +147,8 @@ pub const TextBlock = struct { | ... | @@ -147,15 +147,8 @@ pub const TextBlock = struct { |
| 147 | if (block.aliases) |aliases| { | 147 | if (block.aliases) |aliases| { |
| 148 | allocator.free(aliases); | 148 | allocator.free(aliases); |
| 149 | } | 149 | } |
| 150 | if (block.references) |references| { | 150 | block.relocs.deinit(); |
| 151 | allocator.free(references); | 151 | block.references.deinit(); |
| 152 | } | ||
| 153 | for (block.relocs.items) |reloc| { | ||
| 154 | allocator.destroy(reloc); | ||
| 155 | } | ||
| 156 | if (block.relocs) |relocs| { | ||
| 157 | allocator.free(relocs); | ||
| 158 | } | ||
| 159 | allocator.free(code); | 152 | allocator.free(code); |
| 160 | } | 153 | } |
| 161 | 154 | ||
| ... | @@ -168,12 +161,19 @@ pub const TextBlock = struct { | ... | @@ -168,12 +161,19 @@ pub const TextBlock = struct { |
| 168 | log.warn(" | {}: {}", .{ index, zld.locals.items[index] }); | 161 | log.warn(" | {}: {}", .{ index, zld.locals.items[index] }); |
| 169 | } | 162 | } |
| 170 | } | 163 | } |
| 171 | if (self.references) |references| { | 164 | if (self.references.count() > 0) { |
| 172 | log.warn(" | References:", .{}); | 165 | log.warn(" | References:", .{}); |
| 173 | for (references) |index| { | 166 | for (self.references.keys()) |index| { |
| 174 | log.warn(" | {}: {}", .{ index, zld.locals.items[index] }); | 167 | log.warn(" | {}: {}", .{ index, zld.locals.items[index] }); |
| 175 | } | 168 | } |
| 176 | } | 169 | } |
| 170 | log.warn(" | code.len = {}", .{self.code.len}); | ||
| 171 | if (self.relocs.items.len > 0) { | ||
| 172 | log.warn("Relocations:", .{}); | ||
| 173 | for (self.relocs.items) |rel| { | ||
| 174 | log.warn(" | {}", .{rel}); | ||
| 175 | } | ||
| 176 | } | ||
| 177 | log.warn(" | size = {}", .{self.size}); | 177 | log.warn(" | size = {}", .{self.size}); |
| 178 | log.warn(" | align = {}", .{self.alignment}); | 178 | log.warn(" | align = {}", .{self.alignment}); |
| 179 | } | 179 | } |
| ... | @@ -280,7 +280,6 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg | ... | @@ -280,7 +280,6 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg |
| 280 | try self.resolveSymbols(); | 280 | try self.resolveSymbols(); |
| 281 | try self.parseTextBlocks(); | 281 | try self.parseTextBlocks(); |
| 282 | return error.TODO; | 282 | return error.TODO; |
| 283 | // try self.resolveStubsAndGotEntries(); | ||
| 284 | // try self.updateMetadata(); | 283 | // try self.updateMetadata(); |
| 285 | // try self.sortSections(); | 284 | // try self.sortSections(); |
| 286 | // try self.addRpaths(args.rpaths); | 285 | // try self.addRpaths(args.rpaths); |
| ... | @@ -1603,7 +1602,9 @@ fn resolveSymbols(self: *Zld) !void { | ... | @@ -1603,7 +1602,9 @@ fn resolveSymbols(self: *Zld) !void { |
| 1603 | 1602 | ||
| 1604 | block.* = .{ | 1603 | block.* = .{ |
| 1605 | .local_sym_index = local_sym_index, | 1604 | .local_sym_index = local_sym_index, |
| 1605 | .references = std.AutoArrayHashMap(u32, void).init(self.allocator), | ||
| 1606 | .code = code, | 1606 | .code = code, |
| 1607 | .relocs = std.ArrayList(*Relocation).init(self.allocator), | ||
| 1607 | .size = size, | 1608 | .size = size, |
| 1608 | .alignment = alignment, | 1609 | .alignment = alignment, |
| 1609 | }; | 1610 | }; |
| ... | @@ -1624,6 +1625,9 @@ fn resolveSymbols(self: *Zld) !void { | ... | @@ -1624,6 +1625,9 @@ fn resolveSymbols(self: *Zld) !void { |
| 1624 | { | 1625 | { |
| 1625 | // Put dyld_stub_binder as an undefined special symbol. | 1626 | // Put dyld_stub_binder as an undefined special symbol. |
| 1626 | const symbol = try Symbol.new(self.allocator, "dyld_stub_binder"); | 1627 | const symbol = try Symbol.new(self.allocator, "dyld_stub_binder"); |
| 1628 | const index = @intCast(u32, self.got_entries.items.len); | ||
| 1629 | symbol.got_index = index; | ||
| 1630 | try self.got_entries.append(self.allocator, symbol); | ||
| 1627 | try self.globals.putNoClobber(self.allocator, symbol.name, symbol); | 1631 | try self.globals.putNoClobber(self.allocator, symbol.name, symbol); |
| 1628 | } | 1632 | } |
| 1629 | 1633 | ||
| ... | @@ -1699,54 +1703,6 @@ fn parseTextBlocks(self: *Zld) !void { | ... | @@ -1699,54 +1703,6 @@ fn parseTextBlocks(self: *Zld) !void { |
| 1699 | } | 1703 | } |
| 1700 | } | 1704 | } |
| 1701 | 1705 | ||
| 1702 | fn resolveStubsAndGotEntries(self: *Zld) !void { | ||
| 1703 | for (self.objects.items) |object| { | ||
| 1704 | log.debug("resolving stubs and got entries from {s}", .{object.name}); | ||
| 1705 | |||
| 1706 | for (object.sections.items) |sect| { | ||
| 1707 | const relocs = sect.relocs orelse continue; | ||
| 1708 | for (relocs) |rel| { | ||
| 1709 | switch (rel.@"type") { | ||
| 1710 | .unsigned => continue, | ||
| 1711 | .got_page, .got_page_off, .got_load, .got, .pointer_to_got => { | ||
| 1712 | const sym = object.symbols.items[rel.target.symbol]; | ||
| 1713 | if (sym.got_index != null) continue; | ||
| 1714 | |||
| 1715 | const index = @intCast(u32, self.got_entries.items.len); | ||
| 1716 | sym.got_index = index; | ||
| 1717 | try self.got_entries.append(self.allocator, sym); | ||
| 1718 | |||
| 1719 | log.debug(" | found GOT entry {s}: {*}", .{ sym.name, sym }); | ||
| 1720 | }, | ||
| 1721 | else => { | ||
| 1722 | if (rel.target != .symbol) continue; | ||
| 1723 | |||
| 1724 | const sym = object.symbols.items[rel.target.symbol]; | ||
| 1725 | assert(sym.payload != .undef); | ||
| 1726 | |||
| 1727 | if (sym.stubs_index != null) continue; | ||
| 1728 | if (sym.payload != .proxy) continue; | ||
| 1729 | |||
| 1730 | const index = @intCast(u32, self.stubs.items.len); | ||
| 1731 | sym.stubs_index = index; | ||
| 1732 | try self.stubs.append(self.allocator, sym); | ||
| 1733 | |||
| 1734 | log.debug(" | found stub {s}: {*}", .{ sym.name, sym }); | ||
| 1735 | }, | ||
| 1736 | } | ||
| 1737 | } | ||
| 1738 | } | ||
| 1739 | } | ||
| 1740 | |||
| 1741 | // Finally, put dyld_stub_binder as the final GOT entry | ||
| 1742 | const sym = self.globals.get("dyld_stub_binder") orelse unreachable; | ||
| 1743 | const index = @intCast(u32, self.got_entries.items.len); | ||
| 1744 | sym.got_index = index; | ||
| 1745 | try self.got_entries.append(self.allocator, sym); | ||
| 1746 | |||
| 1747 | log.debug(" | found GOT entry {s}: {*}", .{ sym.name, sym }); | ||
| 1748 | } | ||
| 1749 | |||
| 1750 | fn resolveRelocsAndWriteSections(self: *Zld) !void { | 1706 | fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1751 | for (self.objects.items) |object| { | 1707 | for (self.objects.items) |object| { |
| 1752 | log.debug("relocating object {s}", .{object.name}); | 1708 | log.debug("relocating object {s}", .{object.name}); |
src/link/MachO/reloc.zig+88-127| ... | @@ -6,16 +6,18 @@ const math = std.math; | ... | @@ -6,16 +6,18 @@ const math = std.math; |
| 6 | const mem = std.mem; | 6 | const mem = std.mem; |
| 7 | const meta = std.meta; | 7 | const meta = std.meta; |
| 8 | 8 | ||
| 9 | const aarch64 = @import("reloc/aarch64.zig"); | 9 | pub const aarch64 = @import("reloc/aarch64.zig"); |
| 10 | const x86_64 = @import("reloc/x86_64.zig"); | 10 | pub const x86_64 = @import("reloc/x86_64.zig"); |
| 11 | 11 | ||
| 12 | const Allocator = mem.Allocator; | 12 | const Allocator = mem.Allocator; |
| 13 | const Symbol = @import("Symbol.zig"); | ||
| 14 | const TextBlock = @import("Zld.zig").TextBlock; | ||
| 13 | 15 | ||
| 14 | pub const Relocation = struct { | 16 | pub const Relocation = struct { |
| 15 | @"type": Type, | 17 | @"type": Type, |
| 16 | code: []u8, | ||
| 17 | offset: u32, | 18 | offset: u32, |
| 18 | target: Target, | 19 | block: *TextBlock, |
| 20 | target: *Symbol, | ||
| 19 | 21 | ||
| 20 | pub fn cast(base: *Relocation, comptime T: type) ?*T { | 22 | pub fn cast(base: *Relocation, comptime T: type) ?*T { |
| 21 | if (base.@"type" != T.base_type) | 23 | if (base.@"type" != T.base_type) |
| ... | @@ -24,43 +26,24 @@ pub const Relocation = struct { | ... | @@ -24,43 +26,24 @@ pub const Relocation = struct { |
| 24 | return @fieldParentPtr(T, "base", base); | 26 | return @fieldParentPtr(T, "base", base); |
| 25 | } | 27 | } |
| 26 | 28 | ||
| 27 | pub const ResolveArgs = struct { | 29 | // pub fn resolve(base: *Relocation) !void { |
| 28 | source_addr: u64, | 30 | // return switch (base.@"type") { |
| 29 | target_addr: u64, | 31 | // .unsigned => @fieldParentPtr(Unsigned, "base", base).resolve(), |
| 30 | subtractor: ?u64 = null, | 32 | // .branch_aarch64 => @fieldParentPtr(aarch64.Branch, "base", base).resolve(), |
| 31 | source_source_sect_addr: ?u64 = null, | 33 | // .page => @fieldParentPtr(aarch64.Page, "base", base).resolve(), |
| 32 | source_target_sect_addr: ?u64 = null, | 34 | // .page_off => @fieldParentPtr(aarch64.PageOff, "base", base).resolve(), |
| 33 | }; | 35 | // .got_page => @fieldParentPtr(aarch64.GotPage, "base", base).resolve(), |
| 34 | 36 | // .got_page_off => @fieldParentPtr(aarch64.GotPageOff, "base", base).resolve(), | |
| 35 | pub fn resolve(base: *Relocation, args: ResolveArgs) !void { | 37 | // .pointer_to_got => @fieldParentPtr(aarch64.PointerToGot, "base", base).resolve(), |
| 36 | log.debug("{s}", .{base.@"type"}); | 38 | // .tlvp_page => @fieldParentPtr(aarch64.TlvpPage, "base", base).resolve(), |
| 37 | log.debug(" | offset 0x{x}", .{base.offset}); | 39 | // .tlvp_page_off => @fieldParentPtr(aarch64.TlvpPageOff, "base", base).resolve(), |
| 38 | log.debug(" | source address 0x{x}", .{args.source_addr}); | 40 | // .branch_x86_64 => @fieldParentPtr(x86_64.Branch, "base", base).resolve(), |
| 39 | log.debug(" | target address 0x{x}", .{args.target_addr}); | 41 | // .signed => @fieldParentPtr(x86_64.Signed, "base", base).resolve(), |
| 40 | if (args.subtractor) |sub| | 42 | // .got_load => @fieldParentPtr(x86_64.GotLoad, "base", base).resolve(), |
| 41 | log.debug(" | subtractor address 0x{x}", .{sub}); | 43 | // .got => @fieldParentPtr(x86_64.Got, "base", base).resolve(), |
| 42 | if (args.source_source_sect_addr) |addr| | 44 | // .tlv => @fieldParentPtr(x86_64.Tlv, "base", base).resolve(), |
| 43 | log.debug(" | source source section address 0x{x}", .{addr}); | 45 | // }; |
| 44 | if (args.source_target_sect_addr) |addr| | 46 | // } |
| 45 | log.debug(" | source target section address 0x{x}", .{addr}); | ||
| 46 | |||
| 47 | return switch (base.@"type") { | ||
| 48 | .unsigned => @fieldParentPtr(Unsigned, "base", base).resolve(args), | ||
| 49 | .branch_aarch64 => @fieldParentPtr(aarch64.Branch, "base", base).resolve(args), | ||
| 50 | .page => @fieldParentPtr(aarch64.Page, "base", base).resolve(args), | ||
| 51 | .page_off => @fieldParentPtr(aarch64.PageOff, "base", base).resolve(args), | ||
| 52 | .got_page => @fieldParentPtr(aarch64.GotPage, "base", base).resolve(args), | ||
| 53 | .got_page_off => @fieldParentPtr(aarch64.GotPageOff, "base", base).resolve(args), | ||
| 54 | .pointer_to_got => @fieldParentPtr(aarch64.PointerToGot, "base", base).resolve(args), | ||
| 55 | .tlvp_page => @fieldParentPtr(aarch64.TlvpPage, "base", base).resolve(args), | ||
| 56 | .tlvp_page_off => @fieldParentPtr(aarch64.TlvpPageOff, "base", base).resolve(args), | ||
| 57 | .branch_x86_64 => @fieldParentPtr(x86_64.Branch, "base", base).resolve(args), | ||
| 58 | .signed => @fieldParentPtr(x86_64.Signed, "base", base).resolve(args), | ||
| 59 | .got_load => @fieldParentPtr(x86_64.GotLoad, "base", base).resolve(args), | ||
| 60 | .got => @fieldParentPtr(x86_64.Got, "base", base).resolve(args), | ||
| 61 | .tlv => @fieldParentPtr(x86_64.Tlv, "base", base).resolve(args), | ||
| 62 | }; | ||
| 63 | } | ||
| 64 | 47 | ||
| 65 | pub const Type = enum { | 48 | pub const Type = enum { |
| 66 | branch_aarch64, | 49 | branch_aarch64, |
| ... | @@ -79,23 +62,37 @@ pub const Relocation = struct { | ... | @@ -79,23 +62,37 @@ pub const Relocation = struct { |
| 79 | tlv, | 62 | tlv, |
| 80 | }; | 63 | }; |
| 81 | 64 | ||
| 82 | pub const Target = union(enum) { | 65 | pub fn format(base: *const Relocation, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { |
| 83 | symbol: u32, | 66 | try std.fmt.format(writer, "Relocation {{ ", .{}); |
| 84 | section: u16, | 67 | try std.fmt.format(writer, ".type = {s}, ", .{base.@"type"}); |
| 68 | try std.fmt.format(writer, ".offset = {}, ", .{base.offset}); | ||
| 69 | try std.fmt.format(writer, ".block = {}", .{base.block.local_sym_index}); | ||
| 70 | try std.fmt.format(writer, ".target = {}, ", .{base.target}); | ||
| 71 | |||
| 72 | try switch (base.@"type") { | ||
| 73 | .unsigned => @fieldParentPtr(Unsigned, "base", base).format(fmt, options, writer), | ||
| 74 | .branch_aarch64 => @fieldParentPtr(aarch64.Branch, "base", base).format(fmt, options, writer), | ||
| 75 | .page => @fieldParentPtr(aarch64.Page, "base", base).format(fmt, options, writer), | ||
| 76 | .page_off => @fieldParentPtr(aarch64.PageOff, "base", base).format(fmt, options, writer), | ||
| 77 | .got_page => @fieldParentPtr(aarch64.GotPage, "base", base).format(fmt, options, writer), | ||
| 78 | .got_page_off => @fieldParentPtr(aarch64.GotPageOff, "base", base).format(fmt, options, writer), | ||
| 79 | .pointer_to_got => @fieldParentPtr(aarch64.PointerToGot, "base", base).format(fmt, options, writer), | ||
| 80 | .tlvp_page => @fieldParentPtr(aarch64.TlvpPage, "base", base).format(fmt, options, writer), | ||
| 81 | .tlvp_page_off => @fieldParentPtr(aarch64.TlvpPageOff, "base", base).format(fmt, options, writer), | ||
| 82 | .branch_x86_64 => @fieldParentPtr(x86_64.Branch, "base", base).format(fmt, options, writer), | ||
| 83 | .signed => @fieldParentPtr(x86_64.Signed, "base", base).format(fmt, options, writer), | ||
| 84 | .got_load => @fieldParentPtr(x86_64.GotLoad, "base", base).format(fmt, options, writer), | ||
| 85 | .got => @fieldParentPtr(x86_64.Got, "base", base).format(fmt, options, writer), | ||
| 86 | .tlv => @fieldParentPtr(x86_64.Tlv, "base", base).format(fmt, options, writer), | ||
| 87 | }; | ||
| 85 | 88 | ||
| 86 | pub fn fromReloc(reloc: macho.relocation_info) Target { | 89 | try std.fmt.format(writer, "}}", .{}); |
| 87 | return if (reloc.r_extern == 1) .{ | 90 | } |
| 88 | .symbol = reloc.r_symbolnum, | ||
| 89 | } else .{ | ||
| 90 | .section = @intCast(u16, reloc.r_symbolnum - 1), | ||
| 91 | }; | ||
| 92 | } | ||
| 93 | }; | ||
| 94 | }; | 91 | }; |
| 95 | 92 | ||
| 96 | pub const Unsigned = struct { | 93 | pub const Unsigned = struct { |
| 97 | base: Relocation, | 94 | base: Relocation, |
| 98 | subtractor: ?Relocation.Target = null, | 95 | subtractor: ?*Symbol = null, |
| 99 | /// Addend embedded directly in the relocation slot | 96 | /// Addend embedded directly in the relocation slot |
| 100 | addend: i64, | 97 | addend: i64, |
| 101 | /// Extracted from r_length: | 98 | /// Extracted from r_length: |
| ... | @@ -106,75 +103,47 @@ pub const Unsigned = struct { | ... | @@ -106,75 +103,47 @@ pub const Unsigned = struct { |
| 106 | 103 | ||
| 107 | pub const base_type: Relocation.Type = .unsigned; | 104 | pub const base_type: Relocation.Type = .unsigned; |
| 108 | 105 | ||
| 109 | pub fn resolve(unsigned: Unsigned, args: Relocation.ResolveArgs) !void { | 106 | // pub fn resolve(unsigned: Unsigned) !void { |
| 110 | const addend = if (unsigned.base.target == .section) | 107 | // const addend = if (unsigned.base.target == .section) |
| 111 | unsigned.addend - @intCast(i64, args.source_target_sect_addr.?) | 108 | // unsigned.addend - @intCast(i64, args.source_target_sect_addr.?) |
| 112 | else | 109 | // else |
| 113 | unsigned.addend; | 110 | // unsigned.addend; |
| 114 | 111 | ||
| 115 | const result = if (args.subtractor) |subtractor| | 112 | // const result = if (args.subtractor) |subtractor| |
| 116 | @intCast(i64, args.target_addr) - @intCast(i64, subtractor) + addend | 113 | // @intCast(i64, args.target_addr) - @intCast(i64, subtractor) + addend |
| 117 | else | 114 | // else |
| 118 | @intCast(i64, args.target_addr) + addend; | 115 | // @intCast(i64, args.target_addr) + addend; |
| 119 | 116 | ||
| 120 | log.debug(" | calculated addend 0x{x}", .{addend}); | 117 | // log.debug(" | calculated addend 0x{x}", .{addend}); |
| 121 | log.debug(" | calculated unsigned value 0x{x}", .{result}); | 118 | // log.debug(" | calculated unsigned value 0x{x}", .{result}); |
| 122 | 119 | ||
| 123 | if (unsigned.is_64bit) { | 120 | // if (unsigned.is_64bit) { |
| 124 | mem.writeIntLittle( | 121 | // mem.writeIntLittle( |
| 125 | u64, | 122 | // u64, |
| 126 | unsigned.base.code[0..8], | 123 | // unsigned.base.code[0..8], |
| 127 | @bitCast(u64, result), | 124 | // @bitCast(u64, result), |
| 128 | ); | 125 | // ); |
| 129 | } else { | 126 | // } else { |
| 130 | mem.writeIntLittle( | 127 | // mem.writeIntLittle( |
| 131 | u32, | 128 | // u32, |
| 132 | unsigned.base.code[0..4], | 129 | // unsigned.base.code[0..4], |
| 133 | @truncate(u32, @bitCast(u64, result)), | 130 | // @truncate(u32, @bitCast(u64, result)), |
| 134 | ); | 131 | // ); |
| 132 | // } | ||
| 133 | // } | ||
| 134 | |||
| 135 | pub fn format(self: Unsigned, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | ||
| 136 | _ = fmt; | ||
| 137 | _ = options; | ||
| 138 | if (self.subtractor) |sub| { | ||
| 139 | try std.fmt.format(writer, ".subtractor = {}, ", .{sub}); | ||
| 135 | } | 140 | } |
| 141 | try std.fmt.format(writer, ".addend = {}, ", .{self.addend}); | ||
| 142 | const length: usize = if (self.is_64bit) 8 else 4; | ||
| 143 | try std.fmt.format(writer, ".length = {}, ", .{length}); | ||
| 136 | } | 144 | } |
| 137 | }; | 145 | }; |
| 138 | 146 | ||
| 139 | pub fn parse( | ||
| 140 | allocator: *Allocator, | ||
| 141 | arch: std.Target.Cpu.Arch, | ||
| 142 | code: []u8, | ||
| 143 | relocs: []const macho.relocation_info, | ||
| 144 | ) ![]*Relocation { | ||
| 145 | var it = RelocIterator{ | ||
| 146 | .buffer = relocs, | ||
| 147 | }; | ||
| 148 | |||
| 149 | switch (arch) { | ||
| 150 | .aarch64 => { | ||
| 151 | var parser = aarch64.Parser{ | ||
| 152 | .allocator = allocator, | ||
| 153 | .it = &it, | ||
| 154 | .code = code, | ||
| 155 | .parsed = std.ArrayList(*Relocation).init(allocator), | ||
| 156 | }; | ||
| 157 | defer parser.deinit(); | ||
| 158 | try parser.parse(); | ||
| 159 | |||
| 160 | return parser.parsed.toOwnedSlice(); | ||
| 161 | }, | ||
| 162 | .x86_64 => { | ||
| 163 | var parser = x86_64.Parser{ | ||
| 164 | .allocator = allocator, | ||
| 165 | .it = &it, | ||
| 166 | .code = code, | ||
| 167 | .parsed = std.ArrayList(*Relocation).init(allocator), | ||
| 168 | }; | ||
| 169 | defer parser.deinit(); | ||
| 170 | try parser.parse(); | ||
| 171 | |||
| 172 | return parser.parsed.toOwnedSlice(); | ||
| 173 | }, | ||
| 174 | else => unreachable, | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | pub const RelocIterator = struct { | 147 | pub const RelocIterator = struct { |
| 179 | buffer: []const macho.relocation_info, | 148 | buffer: []const macho.relocation_info, |
| 180 | index: i32 = -1, | 149 | index: i32 = -1, |
| ... | @@ -182,15 +151,7 @@ pub const RelocIterator = struct { | ... | @@ -182,15 +151,7 @@ pub const RelocIterator = struct { |
| 182 | pub fn next(self: *RelocIterator) ?macho.relocation_info { | 151 | pub fn next(self: *RelocIterator) ?macho.relocation_info { |
| 183 | self.index += 1; | 152 | self.index += 1; |
| 184 | if (self.index < self.buffer.len) { | 153 | if (self.index < self.buffer.len) { |
| 185 | const reloc = self.buffer[@intCast(u32, self.index)]; | 154 | return self.buffer[@intCast(u32, self.index)]; |
| 186 | log.debug("relocation", .{}); | ||
| 187 | log.debug(" | type = {}", .{reloc.r_type}); | ||
| 188 | log.debug(" | offset = {}", .{reloc.r_address}); | ||
| 189 | log.debug(" | PC = {}", .{reloc.r_pcrel == 1}); | ||
| 190 | log.debug(" | length = {}", .{reloc.r_length}); | ||
| 191 | log.debug(" | symbolnum = {}", .{reloc.r_symbolnum}); | ||
| 192 | log.debug(" | extern = {}", .{reloc.r_extern == 1}); | ||
| 193 | return reloc; | ||
| 194 | } | 155 | } |
| 195 | return null; | 156 | return null; |
| 196 | } | 157 | } |
src/link/MachO/reloc/aarch64.zig+278-287| ... | @@ -9,24 +9,34 @@ const meta = std.meta; | ... | @@ -9,24 +9,34 @@ const meta = std.meta; |
| 9 | const reloc = @import("../reloc.zig"); | 9 | const reloc = @import("../reloc.zig"); |
| 10 | 10 | ||
| 11 | const Allocator = mem.Allocator; | 11 | const Allocator = mem.Allocator; |
| 12 | const Object = @import("../Object.zig"); | ||
| 12 | const Relocation = reloc.Relocation; | 13 | const Relocation = reloc.Relocation; |
| 13 | const Symbol = @import("../Symbol.zig"); | 14 | const Symbol = @import("../Symbol.zig"); |
| 15 | const TextBlock = Zld.TextBlock; | ||
| 16 | const Zld = @import("../Zld.zig"); | ||
| 14 | 17 | ||
| 15 | pub const Branch = struct { | 18 | pub const Branch = struct { |
| 16 | base: Relocation, | 19 | base: Relocation, |
| 17 | /// Always .UnconditionalBranchImmediate | 20 | /// Always .UnconditionalBranchImmediate |
| 18 | inst: aarch64.Instruction, | 21 | // inst: aarch64.Instruction, |
| 19 | 22 | ||
| 20 | pub const base_type: Relocation.Type = .branch_aarch64; | 23 | pub const base_type: Relocation.Type = .branch_aarch64; |
| 21 | 24 | ||
| 22 | pub fn resolve(branch: Branch, args: Relocation.ResolveArgs) !void { | 25 | // pub fn resolve(branch: Branch, args: Relocation.ResolveArgs) !void { |
| 23 | const displacement = try math.cast(i28, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr)); | 26 | // const displacement = try math.cast(i28, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr)); |
| 24 | 27 | ||
| 25 | log.debug(" | displacement 0x{x}", .{displacement}); | 28 | // log.debug(" | displacement 0x{x}", .{displacement}); |
| 26 | 29 | ||
| 27 | var inst = branch.inst; | 30 | // var inst = branch.inst; |
| 28 | inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2)); | 31 | // inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2)); |
| 29 | mem.writeIntLittle(u32, branch.base.code[0..4], inst.toU32()); | 32 | // mem.writeIntLittle(u32, branch.base.code[0..4], inst.toU32()); |
| 33 | // } | ||
| 34 | |||
| 35 | pub fn format(self: Branch, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | ||
| 36 | _ = self; | ||
| 37 | _ = fmt; | ||
| 38 | _ = options; | ||
| 39 | _ = writer; | ||
| 30 | } | 40 | } |
| 31 | }; | 41 | }; |
| 32 | 42 | ||
| ... | @@ -34,24 +44,32 @@ pub const Page = struct { | ... | @@ -34,24 +44,32 @@ pub const Page = struct { |
| 34 | base: Relocation, | 44 | base: Relocation, |
| 35 | addend: ?u32 = null, | 45 | addend: ?u32 = null, |
| 36 | /// Always .PCRelativeAddress | 46 | /// Always .PCRelativeAddress |
| 37 | inst: aarch64.Instruction, | 47 | // inst: aarch64.Instruction, |
| 38 | 48 | ||
| 39 | pub const base_type: Relocation.Type = .page; | 49 | pub const base_type: Relocation.Type = .page; |
| 40 | 50 | ||
| 41 | pub fn resolve(page: Page, args: Relocation.ResolveArgs) !void { | 51 | // pub fn resolve(page: Page, args: Relocation.ResolveArgs) !void { |
| 42 | const target_addr = if (page.addend) |addend| args.target_addr + addend else args.target_addr; | 52 | // const target_addr = if (page.addend) |addend| args.target_addr + addend else args.target_addr; |
| 43 | const source_page = @intCast(i32, args.source_addr >> 12); | 53 | // const source_page = @intCast(i32, args.source_addr >> 12); |
| 44 | const target_page = @intCast(i32, target_addr >> 12); | 54 | // const target_page = @intCast(i32, target_addr >> 12); |
| 45 | const pages = @bitCast(u21, @intCast(i21, target_page - source_page)); | 55 | // const pages = @bitCast(u21, @intCast(i21, target_page - source_page)); |
| 56 | |||
| 57 | // log.debug(" | calculated addend 0x{x}", .{page.addend}); | ||
| 58 | // log.debug(" | moving by {} pages", .{pages}); | ||
| 46 | 59 | ||
| 47 | log.debug(" | calculated addend 0x{x}", .{page.addend}); | 60 | // var inst = page.inst; |
| 48 | log.debug(" | moving by {} pages", .{pages}); | 61 | // inst.pc_relative_address.immhi = @truncate(u19, pages >> 2); |
| 62 | // inst.pc_relative_address.immlo = @truncate(u2, pages); | ||
| 49 | 63 | ||
| 50 | var inst = page.inst; | 64 | // mem.writeIntLittle(u32, page.base.code[0..4], inst.toU32()); |
| 51 | inst.pc_relative_address.immhi = @truncate(u19, pages >> 2); | 65 | // } |
| 52 | inst.pc_relative_address.immlo = @truncate(u2, pages); | ||
| 53 | 66 | ||
| 54 | mem.writeIntLittle(u32, page.base.code[0..4], inst.toU32()); | 67 | pub fn format(self: Page, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { |
| 68 | _ = fmt; | ||
| 69 | _ = options; | ||
| 70 | if (self.addend) |addend| { | ||
| 71 | try std.fmt.format(writer, ".addend = {}, ", .{addend}); | ||
| 72 | } | ||
| 55 | } | 73 | } |
| 56 | }; | 74 | }; |
| 57 | 75 | ||
| ... | @@ -59,7 +77,7 @@ pub const PageOff = struct { | ... | @@ -59,7 +77,7 @@ pub const PageOff = struct { |
| 59 | base: Relocation, | 77 | base: Relocation, |
| 60 | addend: ?u32 = null, | 78 | addend: ?u32 = null, |
| 61 | op_kind: OpKind, | 79 | op_kind: OpKind, |
| 62 | inst: aarch64.Instruction, | 80 | // inst: aarch64.Instruction, |
| 63 | 81 | ||
| 64 | pub const base_type: Relocation.Type = .page_off; | 82 | pub const base_type: Relocation.Type = .page_off; |
| 65 | 83 | ||
| ... | @@ -68,76 +86,99 @@ pub const PageOff = struct { | ... | @@ -68,76 +86,99 @@ pub const PageOff = struct { |
| 68 | load_store, | 86 | load_store, |
| 69 | }; | 87 | }; |
| 70 | 88 | ||
| 71 | pub fn resolve(page_off: PageOff, args: Relocation.ResolveArgs) !void { | 89 | // pub fn resolve(page_off: PageOff, args: Relocation.ResolveArgs) !void { |
| 72 | const target_addr = if (page_off.addend) |addend| args.target_addr + addend else args.target_addr; | 90 | // const target_addr = if (page_off.addend) |addend| args.target_addr + addend else args.target_addr; |
| 73 | const narrowed = @truncate(u12, target_addr); | 91 | // const narrowed = @truncate(u12, target_addr); |
| 74 | 92 | ||
| 75 | log.debug(" | narrowed address within the page 0x{x}", .{narrowed}); | 93 | // log.debug(" | narrowed address within the page 0x{x}", .{narrowed}); |
| 76 | log.debug(" | {s} opcode", .{page_off.op_kind}); | 94 | // log.debug(" | {s} opcode", .{page_off.op_kind}); |
| 77 | 95 | ||
| 78 | var inst = page_off.inst; | 96 | // var inst = page_off.inst; |
| 79 | if (page_off.op_kind == .arithmetic) { | 97 | // if (page_off.op_kind == .arithmetic) { |
| 80 | inst.add_subtract_immediate.imm12 = narrowed; | 98 | // inst.add_subtract_immediate.imm12 = narrowed; |
| 81 | } else { | 99 | // } else { |
| 82 | const offset: u12 = blk: { | 100 | // const offset: u12 = blk: { |
| 83 | if (inst.load_store_register.size == 0) { | 101 | // if (inst.load_store_register.size == 0) { |
| 84 | if (inst.load_store_register.v == 1) { | 102 | // if (inst.load_store_register.v == 1) { |
| 85 | // 128-bit SIMD is scaled by 16. | 103 | // // 128-bit SIMD is scaled by 16. |
| 86 | break :blk try math.divExact(u12, narrowed, 16); | 104 | // break :blk try math.divExact(u12, narrowed, 16); |
| 87 | } | 105 | // } |
| 88 | // Otherwise, 8-bit SIMD or ldrb. | 106 | // // Otherwise, 8-bit SIMD or ldrb. |
| 89 | break :blk narrowed; | 107 | // break :blk narrowed; |
| 90 | } else { | 108 | // } else { |
| 91 | const denom: u4 = try math.powi(u4, 2, inst.load_store_register.size); | 109 | // const denom: u4 = try math.powi(u4, 2, inst.load_store_register.size); |
| 92 | break :blk try math.divExact(u12, narrowed, denom); | 110 | // break :blk try math.divExact(u12, narrowed, denom); |
| 93 | } | 111 | // } |
| 94 | }; | 112 | // }; |
| 95 | inst.load_store_register.offset = offset; | 113 | // inst.load_store_register.offset = offset; |
| 114 | // } | ||
| 115 | |||
| 116 | // mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32()); | ||
| 117 | // } | ||
| 118 | |||
| 119 | pub fn format(self: PageOff, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | ||
| 120 | _ = fmt; | ||
| 121 | _ = options; | ||
| 122 | if (self.addend) |addend| { | ||
| 123 | try std.fmt.format(writer, ".addend = {}, ", .{addend}); | ||
| 96 | } | 124 | } |
| 97 | 125 | try std.fmt.format(writer, ".op_kind = {s}, ", .{self.op_kind}); | |
| 98 | mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32()); | ||
| 99 | } | 126 | } |
| 100 | }; | 127 | }; |
| 101 | 128 | ||
| 102 | pub const GotPage = struct { | 129 | pub const GotPage = struct { |
| 103 | base: Relocation, | 130 | base: Relocation, |
| 104 | /// Always .PCRelativeAddress | 131 | /// Always .PCRelativeAddress |
| 105 | inst: aarch64.Instruction, | 132 | // inst: aarch64.Instruction, |
| 106 | 133 | ||
| 107 | pub const base_type: Relocation.Type = .got_page; | 134 | pub const base_type: Relocation.Type = .got_page; |
| 108 | 135 | ||
| 109 | pub fn resolve(page: GotPage, args: Relocation.ResolveArgs) !void { | 136 | // pub fn resolve(page: GotPage, args: Relocation.ResolveArgs) !void { |
| 110 | const source_page = @intCast(i32, args.source_addr >> 12); | 137 | // const source_page = @intCast(i32, args.source_addr >> 12); |
| 111 | const target_page = @intCast(i32, args.target_addr >> 12); | 138 | // const target_page = @intCast(i32, args.target_addr >> 12); |
| 112 | const pages = @bitCast(u21, @intCast(i21, target_page - source_page)); | 139 | // const pages = @bitCast(u21, @intCast(i21, target_page - source_page)); |
| 113 | 140 | ||
| 114 | log.debug(" | moving by {} pages", .{pages}); | 141 | // log.debug(" | moving by {} pages", .{pages}); |
| 115 | 142 | ||
| 116 | var inst = page.inst; | 143 | // var inst = page.inst; |
| 117 | inst.pc_relative_address.immhi = @truncate(u19, pages >> 2); | 144 | // inst.pc_relative_address.immhi = @truncate(u19, pages >> 2); |
| 118 | inst.pc_relative_address.immlo = @truncate(u2, pages); | 145 | // inst.pc_relative_address.immlo = @truncate(u2, pages); |
| 119 | 146 | ||
| 120 | mem.writeIntLittle(u32, page.base.code[0..4], inst.toU32()); | 147 | // mem.writeIntLittle(u32, page.base.code[0..4], inst.toU32()); |
| 148 | // } | ||
| 149 | |||
| 150 | pub fn format(self: GotPage, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | ||
| 151 | _ = self; | ||
| 152 | _ = fmt; | ||
| 153 | _ = options; | ||
| 154 | _ = writer; | ||
| 121 | } | 155 | } |
| 122 | }; | 156 | }; |
| 123 | 157 | ||
| 124 | pub const GotPageOff = struct { | 158 | pub const GotPageOff = struct { |
| 125 | base: Relocation, | 159 | base: Relocation, |
| 126 | /// Always .LoadStoreRegister with size = 3 for GOT indirection | 160 | /// Always .LoadStoreRegister with size = 3 for GOT indirection |
| 127 | inst: aarch64.Instruction, | 161 | // inst: aarch64.Instruction, |
| 128 | 162 | ||
| 129 | pub const base_type: Relocation.Type = .got_page_off; | 163 | pub const base_type: Relocation.Type = .got_page_off; |
| 130 | 164 | ||
| 131 | pub fn resolve(page_off: GotPageOff, args: Relocation.ResolveArgs) !void { | 165 | // pub fn resolve(page_off: GotPageOff, args: Relocation.ResolveArgs) !void { |
| 132 | const narrowed = @truncate(u12, args.target_addr); | 166 | // const narrowed = @truncate(u12, args.target_addr); |
| 167 | |||
| 168 | // log.debug(" | narrowed address within the page 0x{x}", .{narrowed}); | ||
| 133 | 169 | ||
| 134 | log.debug(" | narrowed address within the page 0x{x}", .{narrowed}); | 170 | // var inst = page_off.inst; |
| 171 | // const offset = try math.divExact(u12, narrowed, 8); | ||
| 172 | // inst.load_store_register.offset = offset; | ||
| 135 | 173 | ||
| 136 | var inst = page_off.inst; | 174 | // mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32()); |
| 137 | const offset = try math.divExact(u12, narrowed, 8); | 175 | // } |
| 138 | inst.load_store_register.offset = offset; | ||
| 139 | 176 | ||
| 140 | mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32()); | 177 | pub fn format(self: GotPageOff, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { |
| 178 | _ = self; | ||
| 179 | _ = fmt; | ||
| 180 | _ = options; | ||
| 181 | _ = writer; | ||
| 141 | } | 182 | } |
| 142 | }; | 183 | }; |
| 143 | 184 | ||
| ... | @@ -146,34 +187,48 @@ pub const PointerToGot = struct { | ... | @@ -146,34 +187,48 @@ pub const PointerToGot = struct { |
| 146 | 187 | ||
| 147 | pub const base_type: Relocation.Type = .pointer_to_got; | 188 | pub const base_type: Relocation.Type = .pointer_to_got; |
| 148 | 189 | ||
| 149 | pub fn resolve(ptr_to_got: PointerToGot, args: Relocation.ResolveArgs) !void { | 190 | // pub fn resolve(ptr_to_got: PointerToGot, args: Relocation.ResolveArgs) !void { |
| 150 | const result = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr)); | 191 | // const result = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr)); |
| 192 | |||
| 193 | // log.debug(" | calculated value 0x{x}", .{result}); | ||
| 151 | 194 | ||
| 152 | log.debug(" | calculated value 0x{x}", .{result}); | 195 | // mem.writeIntLittle(u32, ptr_to_got.base.code[0..4], @bitCast(u32, result)); |
| 196 | // } | ||
| 153 | 197 | ||
| 154 | mem.writeIntLittle(u32, ptr_to_got.base.code[0..4], @bitCast(u32, result)); | 198 | pub fn format(self: PointerToGot, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { |
| 199 | _ = self; | ||
| 200 | _ = fmt; | ||
| 201 | _ = options; | ||
| 202 | _ = writer; | ||
| 155 | } | 203 | } |
| 156 | }; | 204 | }; |
| 157 | 205 | ||
| 158 | pub const TlvpPage = struct { | 206 | pub const TlvpPage = struct { |
| 159 | base: Relocation, | 207 | base: Relocation, |
| 160 | /// Always .PCRelativeAddress | 208 | /// Always .PCRelativeAddress |
| 161 | inst: aarch64.Instruction, | 209 | // inst: aarch64.Instruction, |
| 162 | 210 | ||
| 163 | pub const base_type: Relocation.Type = .tlvp_page; | 211 | pub const base_type: Relocation.Type = .tlvp_page; |
| 164 | 212 | ||
| 165 | pub fn resolve(page: TlvpPage, args: Relocation.ResolveArgs) !void { | 213 | // pub fn resolve(page: TlvpPage, args: Relocation.ResolveArgs) !void { |
| 166 | const source_page = @intCast(i32, args.source_addr >> 12); | 214 | // const source_page = @intCast(i32, args.source_addr >> 12); |
| 167 | const target_page = @intCast(i32, args.target_addr >> 12); | 215 | // const target_page = @intCast(i32, args.target_addr >> 12); |
| 168 | const pages = @bitCast(u21, @intCast(i21, target_page - source_page)); | 216 | // const pages = @bitCast(u21, @intCast(i21, target_page - source_page)); |
| 169 | 217 | ||
| 170 | log.debug(" | moving by {} pages", .{pages}); | 218 | // log.debug(" | moving by {} pages", .{pages}); |
| 171 | 219 | ||
| 172 | var inst = page.inst; | 220 | // var inst = page.inst; |
| 173 | inst.pc_relative_address.immhi = @truncate(u19, pages >> 2); | 221 | // inst.pc_relative_address.immhi = @truncate(u19, pages >> 2); |
| 174 | inst.pc_relative_address.immlo = @truncate(u2, pages); | 222 | // inst.pc_relative_address.immlo = @truncate(u2, pages); |
| 175 | 223 | ||
| 176 | mem.writeIntLittle(u32, page.base.code[0..4], inst.toU32()); | 224 | // mem.writeIntLittle(u32, page.base.code[0..4], inst.toU32()); |
| 225 | // } | ||
| 226 | |||
| 227 | pub fn format(self: TlvpPage, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | ||
| 228 | _ = self; | ||
| 229 | _ = fmt; | ||
| 230 | _ = options; | ||
| 231 | _ = writer; | ||
| 177 | } | 232 | } |
| 178 | }; | 233 | }; |
| 179 | 234 | ||
| ... | @@ -182,82 +237,110 @@ pub const TlvpPageOff = struct { | ... | @@ -182,82 +237,110 @@ pub const TlvpPageOff = struct { |
| 182 | /// Always .AddSubtractImmediate regardless of the source instruction. | 237 | /// Always .AddSubtractImmediate regardless of the source instruction. |
| 183 | /// This means, we always rewrite the instruction to add even if the | 238 | /// This means, we always rewrite the instruction to add even if the |
| 184 | /// source instruction was an ldr. | 239 | /// source instruction was an ldr. |
| 185 | inst: aarch64.Instruction, | 240 | // inst: aarch64.Instruction, |
| 186 | 241 | ||
| 187 | pub const base_type: Relocation.Type = .tlvp_page_off; | 242 | pub const base_type: Relocation.Type = .tlvp_page_off; |
| 188 | 243 | ||
| 189 | pub fn resolve(page_off: TlvpPageOff, args: Relocation.ResolveArgs) !void { | 244 | // pub fn resolve(page_off: TlvpPageOff, args: Relocation.ResolveArgs) !void { |
| 190 | const narrowed = @truncate(u12, args.target_addr); | 245 | // const narrowed = @truncate(u12, args.target_addr); |
| 246 | |||
| 247 | // log.debug(" | narrowed address within the page 0x{x}", .{narrowed}); | ||
| 191 | 248 | ||
| 192 | log.debug(" | narrowed address within the page 0x{x}", .{narrowed}); | 249 | // var inst = page_off.inst; |
| 250 | // inst.add_subtract_immediate.imm12 = narrowed; | ||
| 193 | 251 | ||
| 194 | var inst = page_off.inst; | 252 | // mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32()); |
| 195 | inst.add_subtract_immediate.imm12 = narrowed; | 253 | // } |
| 196 | 254 | ||
| 197 | mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32()); | 255 | pub fn format(self: TlvpPageOff, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { |
| 256 | _ = self; | ||
| 257 | _ = fmt; | ||
| 258 | _ = options; | ||
| 259 | _ = writer; | ||
| 198 | } | 260 | } |
| 199 | }; | 261 | }; |
| 200 | 262 | ||
| 201 | pub const Parser = struct { | 263 | pub const Parser = struct { |
| 202 | allocator: *Allocator, | 264 | object: *Object, |
| 265 | zld: *Zld, | ||
| 203 | it: *reloc.RelocIterator, | 266 | it: *reloc.RelocIterator, |
| 204 | code: []u8, | 267 | block: *TextBlock, |
| 205 | parsed: std.ArrayList(*Relocation), | 268 | base_addr: u64, |
| 206 | addend: ?u32 = null, | 269 | addend: ?u32 = null, |
| 207 | subtractor: ?Relocation.Target = null, | 270 | subtractor: ?*Symbol = null, |
| 208 | 271 | ||
| 209 | pub fn deinit(parser: *Parser) void { | 272 | pub fn parse(self: *Parser) !void { |
| 210 | parser.parsed.deinit(); | 273 | while (self.it.next()) |rel| { |
| 211 | } | 274 | const out_rel = switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) { |
| 212 | 275 | .ARM64_RELOC_BRANCH26 => try self.parseBranch(rel), | |
| 213 | pub fn parse(parser: *Parser) !void { | ||
| 214 | while (parser.it.next()) |rel| { | ||
| 215 | switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) { | ||
| 216 | .ARM64_RELOC_BRANCH26 => { | ||
| 217 | try parser.parseBranch(rel); | ||
| 218 | }, | ||
| 219 | .ARM64_RELOC_SUBTRACTOR => { | 276 | .ARM64_RELOC_SUBTRACTOR => { |
| 220 | try parser.parseSubtractor(rel); | 277 | // Subtractor is not a relocation with effect on the TextBlock, so |
| 221 | }, | 278 | // parse it and carry on. |
| 222 | .ARM64_RELOC_UNSIGNED => { | 279 | try self.parseSubtractor(rel); |
| 223 | try parser.parseUnsigned(rel); | 280 | continue; |
| 224 | }, | 281 | }, |
| 282 | .ARM64_RELOC_UNSIGNED => try self.parseUnsigned(rel), | ||
| 225 | .ARM64_RELOC_ADDEND => { | 283 | .ARM64_RELOC_ADDEND => { |
| 226 | try parser.parseAddend(rel); | 284 | // Addend is not a relocation with effect on the TextBlock, so |
| 285 | // parse it and carry on. | ||
| 286 | try self.parseAddend(rel); | ||
| 287 | continue; | ||
| 227 | }, | 288 | }, |
| 228 | .ARM64_RELOC_PAGE21, | 289 | .ARM64_RELOC_PAGE21, |
| 229 | .ARM64_RELOC_GOT_LOAD_PAGE21, | 290 | .ARM64_RELOC_GOT_LOAD_PAGE21, |
| 230 | .ARM64_RELOC_TLVP_LOAD_PAGE21, | 291 | .ARM64_RELOC_TLVP_LOAD_PAGE21, |
| 231 | => { | 292 | => try self.parsePage(rel), |
| 232 | try parser.parsePage(rel); | 293 | .ARM64_RELOC_PAGEOFF12 => try self.parsePageOff(rel), |
| 233 | }, | 294 | .ARM64_RELOC_GOT_LOAD_PAGEOFF12 => try self.parseGotLoadPageOff(rel), |
| 234 | .ARM64_RELOC_PAGEOFF12 => { | 295 | .ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => try self.parseTlvpLoadPageOff(rel), |
| 235 | try parser.parsePageOff(rel); | 296 | .ARM64_RELOC_POINTER_TO_GOT => try self.parsePointerToGot(rel), |
| 236 | }, | 297 | }; |
| 237 | .ARM64_RELOC_GOT_LOAD_PAGEOFF12 => { | 298 | try self.block.relocs.append(out_rel); |
| 238 | try parser.parseGotLoadPageOff(rel); | 299 | |
| 239 | }, | 300 | if (out_rel.target.payload == .regular) { |
| 240 | .ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => { | 301 | try self.block.references.put(out_rel.target.payload.regular.local_sym_index, {}); |
| 241 | try parser.parseTlvpLoadPageOff(rel); | 302 | } |
| 303 | |||
| 304 | switch (out_rel.@"type") { | ||
| 305 | .got_page, .got_page_off, .pointer_to_got => { | ||
| 306 | const sym = out_rel.target; | ||
| 307 | |||
| 308 | if (sym.got_index != null) continue; | ||
| 309 | |||
| 310 | const index = @intCast(u32, self.zld.got_entries.items.len); | ||
| 311 | sym.got_index = index; | ||
| 312 | try self.zld.got_entries.append(self.zld.allocator, sym); | ||
| 313 | |||
| 314 | log.debug("adding GOT entry for symbol {s} at index {}", .{ sym.name, index }); | ||
| 242 | }, | 315 | }, |
| 243 | .ARM64_RELOC_POINTER_TO_GOT => { | 316 | .branch_aarch64 => { |
| 244 | try parser.parsePointerToGot(rel); | 317 | const sym = out_rel.target; |
| 318 | |||
| 319 | if (sym.stubs_index != null) continue; | ||
| 320 | if (sym.payload != .proxy) continue; | ||
| 321 | |||
| 322 | const index = @intCast(u32, self.zld.stubs.items.len); | ||
| 323 | sym.stubs_index = index; | ||
| 324 | try self.zld.stubs.append(self.zld.allocator, sym); | ||
| 325 | |||
| 326 | log.debug("adding stub entry for symbol {s} at index {}", .{ sym.name, index }); | ||
| 245 | }, | 327 | }, |
| 328 | else => {}, | ||
| 246 | } | 329 | } |
| 247 | } | 330 | } |
| 248 | } | 331 | } |
| 249 | 332 | ||
| 250 | fn parseAddend(parser: *Parser, rel: macho.relocation_info) !void { | 333 | fn parseAddend(self: *Parser, rel: macho.relocation_info) !void { |
| 251 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); | 334 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); |
| 252 | assert(rel_type == .ARM64_RELOC_ADDEND); | 335 | assert(rel_type == .ARM64_RELOC_ADDEND); |
| 253 | assert(rel.r_pcrel == 0); | 336 | assert(rel.r_pcrel == 0); |
| 254 | assert(rel.r_extern == 0); | 337 | assert(rel.r_extern == 0); |
| 255 | assert(parser.addend == null); | 338 | assert(self.addend == null); |
| 256 | 339 | ||
| 257 | parser.addend = rel.r_symbolnum; | 340 | self.addend = rel.r_symbolnum; |
| 258 | 341 | ||
| 259 | // Verify ADDEND is followed by a load. | 342 | // Verify ADDEND is followed by a load. |
| 260 | const next = @intToEnum(macho.reloc_type_arm64, parser.it.peek().r_type); | 343 | const next = @intToEnum(macho.reloc_type_arm64, self.it.peek().r_type); |
| 261 | switch (next) { | 344 | switch (next) { |
| 262 | .ARM64_RELOC_PAGE21, .ARM64_RELOC_PAGEOFF12 => {}, | 345 | .ARM64_RELOC_PAGE21, .ARM64_RELOC_PAGEOFF12 => {}, |
| 263 | else => { | 346 | else => { |
| ... | @@ -267,127 +350,101 @@ pub const Parser = struct { | ... | @@ -267,127 +350,101 @@ pub const Parser = struct { |
| 267 | } | 350 | } |
| 268 | } | 351 | } |
| 269 | 352 | ||
| 270 | fn parseBranch(parser: *Parser, rel: macho.relocation_info) !void { | 353 | fn parseBranch(self: *Parser, rel: macho.relocation_info) !*Relocation { |
| 271 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); | 354 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); |
| 272 | assert(rel_type == .ARM64_RELOC_BRANCH26); | 355 | assert(rel_type == .ARM64_RELOC_BRANCH26); |
| 273 | assert(rel.r_pcrel == 1); | 356 | assert(rel.r_pcrel == 1); |
| 274 | assert(rel.r_length == 2); | 357 | assert(rel.r_length == 2); |
| 275 | 358 | ||
| 276 | const offset = @intCast(u32, rel.r_address); | 359 | const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr); |
| 277 | const inst = parser.code[offset..][0..4]; | 360 | const target = try self.object.symbolFromReloc(rel); |
| 278 | const parsed_inst = aarch64.Instruction{ .unconditional_branch_immediate = mem.bytesToValue( | ||
| 279 | meta.TagPayload( | ||
| 280 | aarch64.Instruction, | ||
| 281 | aarch64.Instruction.unconditional_branch_immediate, | ||
| 282 | ), | ||
| 283 | inst, | ||
| 284 | ) }; | ||
| 285 | |||
| 286 | var branch = try parser.allocator.create(Branch); | ||
| 287 | errdefer parser.allocator.destroy(branch); | ||
| 288 | 361 | ||
| 289 | const target = Relocation.Target.fromReloc(rel); | 362 | var branch = try self.object.allocator.create(Branch); |
| 363 | errdefer self.object.allocator.destroy(branch); | ||
| 290 | 364 | ||
| 291 | branch.* = .{ | 365 | branch.* = .{ |
| 292 | .base = .{ | 366 | .base = .{ |
| 293 | .@"type" = .branch_aarch64, | 367 | .@"type" = .branch_aarch64, |
| 294 | .code = inst, | ||
| 295 | .offset = offset, | 368 | .offset = offset, |
| 296 | .target = target, | 369 | .target = target, |
| 370 | .block = self.block, | ||
| 297 | }, | 371 | }, |
| 298 | .inst = parsed_inst, | ||
| 299 | }; | 372 | }; |
| 300 | 373 | ||
| 301 | log.debug(" | emitting {}", .{branch}); | 374 | return &branch.base; |
| 302 | try parser.parsed.append(&branch.base); | ||
| 303 | } | 375 | } |
| 304 | 376 | ||
| 305 | fn parsePage(parser: *Parser, rel: macho.relocation_info) !void { | 377 | fn parsePage(self: *Parser, rel: macho.relocation_info) !*Relocation { |
| 306 | assert(rel.r_pcrel == 1); | 378 | assert(rel.r_pcrel == 1); |
| 307 | assert(rel.r_length == 2); | 379 | assert(rel.r_length == 2); |
| 308 | 380 | ||
| 309 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); | 381 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); |
| 310 | const target = Relocation.Target.fromReloc(rel); | 382 | const target = try self.object.symbolFromReloc(rel); |
| 311 | 383 | const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr); | |
| 312 | const offset = @intCast(u32, rel.r_address); | ||
| 313 | const inst = parser.code[offset..][0..4]; | ||
| 314 | const parsed_inst = aarch64.Instruction{ .pc_relative_address = mem.bytesToValue(meta.TagPayload( | ||
| 315 | aarch64.Instruction, | ||
| 316 | aarch64.Instruction.pc_relative_address, | ||
| 317 | ), inst) }; | ||
| 318 | 384 | ||
| 319 | const ptr: *Relocation = ptr: { | 385 | const ptr: *Relocation = ptr: { |
| 320 | switch (rel_type) { | 386 | switch (rel_type) { |
| 321 | .ARM64_RELOC_PAGE21 => { | 387 | .ARM64_RELOC_PAGE21 => { |
| 322 | defer { | 388 | defer { |
| 323 | // Reset parser's addend state | 389 | // Reset parser's addend state |
| 324 | parser.addend = null; | 390 | self.addend = null; |
| 325 | } | 391 | } |
| 326 | var page = try parser.allocator.create(Page); | 392 | var page = try self.object.allocator.create(Page); |
| 327 | errdefer parser.allocator.destroy(page); | 393 | errdefer self.object.allocator.destroy(page); |
| 328 | 394 | ||
| 329 | page.* = .{ | 395 | page.* = .{ |
| 330 | .base = .{ | 396 | .base = .{ |
| 331 | .@"type" = .page, | 397 | .@"type" = .page, |
| 332 | .code = inst, | ||
| 333 | .offset = offset, | 398 | .offset = offset, |
| 334 | .target = target, | 399 | .target = target, |
| 400 | .block = self.block, | ||
| 335 | }, | 401 | }, |
| 336 | .addend = parser.addend, | 402 | .addend = self.addend, |
| 337 | .inst = parsed_inst, | ||
| 338 | }; | 403 | }; |
| 339 | 404 | ||
| 340 | log.debug(" | emitting {}", .{page}); | ||
| 341 | |||
| 342 | break :ptr &page.base; | 405 | break :ptr &page.base; |
| 343 | }, | 406 | }, |
| 344 | .ARM64_RELOC_GOT_LOAD_PAGE21 => { | 407 | .ARM64_RELOC_GOT_LOAD_PAGE21 => { |
| 345 | var page = try parser.allocator.create(GotPage); | 408 | var page = try self.object.allocator.create(GotPage); |
| 346 | errdefer parser.allocator.destroy(page); | 409 | errdefer self.object.allocator.destroy(page); |
| 347 | 410 | ||
| 348 | page.* = .{ | 411 | page.* = .{ |
| 349 | .base = .{ | 412 | .base = .{ |
| 350 | .@"type" = .got_page, | 413 | .@"type" = .got_page, |
| 351 | .code = inst, | ||
| 352 | .offset = offset, | 414 | .offset = offset, |
| 353 | .target = target, | 415 | .target = target, |
| 416 | .block = self.block, | ||
| 354 | }, | 417 | }, |
| 355 | .inst = parsed_inst, | ||
| 356 | }; | 418 | }; |
| 357 | 419 | ||
| 358 | log.debug(" | emitting {}", .{page}); | ||
| 359 | |||
| 360 | break :ptr &page.base; | 420 | break :ptr &page.base; |
| 361 | }, | 421 | }, |
| 362 | .ARM64_RELOC_TLVP_LOAD_PAGE21 => { | 422 | .ARM64_RELOC_TLVP_LOAD_PAGE21 => { |
| 363 | var page = try parser.allocator.create(TlvpPage); | 423 | var page = try self.object.allocator.create(TlvpPage); |
| 364 | errdefer parser.allocator.destroy(page); | 424 | errdefer self.object.allocator.destroy(page); |
| 365 | 425 | ||
| 366 | page.* = .{ | 426 | page.* = .{ |
| 367 | .base = .{ | 427 | .base = .{ |
| 368 | .@"type" = .tlvp_page, | 428 | .@"type" = .tlvp_page, |
| 369 | .code = inst, | ||
| 370 | .offset = offset, | 429 | .offset = offset, |
| 371 | .target = target, | 430 | .target = target, |
| 431 | .block = self.block, | ||
| 372 | }, | 432 | }, |
| 373 | .inst = parsed_inst, | ||
| 374 | }; | 433 | }; |
| 375 | 434 | ||
| 376 | log.debug(" | emitting {}", .{page}); | ||
| 377 | |||
| 378 | break :ptr &page.base; | 435 | break :ptr &page.base; |
| 379 | }, | 436 | }, |
| 380 | else => unreachable, | 437 | else => unreachable, |
| 381 | } | 438 | } |
| 382 | }; | 439 | }; |
| 383 | 440 | ||
| 384 | try parser.parsed.append(ptr); | 441 | return ptr; |
| 385 | } | 442 | } |
| 386 | 443 | ||
| 387 | fn parsePageOff(parser: *Parser, rel: macho.relocation_info) !void { | 444 | fn parsePageOff(self: *Parser, rel: macho.relocation_info) !*Relocation { |
| 388 | defer { | 445 | defer { |
| 389 | // Reset parser's addend state | 446 | // Reset parser's addend state |
| 390 | parser.addend = null; | 447 | self.addend = null; |
| 391 | } | 448 | } |
| 392 | 449 | ||
| 393 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); | 450 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); |
| ... | @@ -395,83 +452,56 @@ pub const Parser = struct { | ... | @@ -395,83 +452,56 @@ pub const Parser = struct { |
| 395 | assert(rel.r_pcrel == 0); | 452 | assert(rel.r_pcrel == 0); |
| 396 | assert(rel.r_length == 2); | 453 | assert(rel.r_length == 2); |
| 397 | 454 | ||
| 398 | const offset = @intCast(u32, rel.r_address); | 455 | const target = try self.object.symbolFromReloc(rel); |
| 399 | const inst = parser.code[offset..][0..4]; | 456 | const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr); |
| 400 | 457 | const op_kind: PageOff.OpKind = if (isArithmeticOp(self.block.code[offset..][0..4])) | |
| 401 | var op_kind: PageOff.OpKind = undefined; | 458 | .arithmetic |
| 402 | var parsed_inst: aarch64.Instruction = undefined; | 459 | else |
| 403 | if (isArithmeticOp(inst)) { | 460 | .load_store; |
| 404 | op_kind = .arithmetic; | ||
| 405 | parsed_inst = .{ .add_subtract_immediate = mem.bytesToValue(meta.TagPayload( | ||
| 406 | aarch64.Instruction, | ||
| 407 | aarch64.Instruction.add_subtract_immediate, | ||
| 408 | ), inst) }; | ||
| 409 | } else { | ||
| 410 | op_kind = .load_store; | ||
| 411 | parsed_inst = .{ .load_store_register = mem.bytesToValue(meta.TagPayload( | ||
| 412 | aarch64.Instruction, | ||
| 413 | aarch64.Instruction.load_store_register, | ||
| 414 | ), inst) }; | ||
| 415 | } | ||
| 416 | const target = Relocation.Target.fromReloc(rel); | ||
| 417 | 461 | ||
| 418 | var page_off = try parser.allocator.create(PageOff); | 462 | var page_off = try self.object.allocator.create(PageOff); |
| 419 | errdefer parser.allocator.destroy(page_off); | 463 | errdefer self.object.allocator.destroy(page_off); |
| 420 | 464 | ||
| 421 | page_off.* = .{ | 465 | page_off.* = .{ |
| 422 | .base = .{ | 466 | .base = .{ |
| 423 | .@"type" = .page_off, | 467 | .@"type" = .page_off, |
| 424 | .code = inst, | ||
| 425 | .offset = offset, | 468 | .offset = offset, |
| 426 | .target = target, | 469 | .target = target, |
| 470 | .block = self.block, | ||
| 427 | }, | 471 | }, |
| 428 | .op_kind = op_kind, | 472 | .op_kind = op_kind, |
| 429 | .inst = parsed_inst, | 473 | .addend = self.addend, |
| 430 | .addend = parser.addend, | ||
| 431 | }; | 474 | }; |
| 432 | 475 | ||
| 433 | log.debug(" | emitting {}", .{page_off}); | 476 | return &page_off.base; |
| 434 | try parser.parsed.append(&page_off.base); | ||
| 435 | } | 477 | } |
| 436 | 478 | ||
| 437 | fn parseGotLoadPageOff(parser: *Parser, rel: macho.relocation_info) !void { | 479 | fn parseGotLoadPageOff(self: *Parser, rel: macho.relocation_info) !*Relocation { |
| 438 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); | 480 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); |
| 439 | assert(rel_type == .ARM64_RELOC_GOT_LOAD_PAGEOFF12); | 481 | assert(rel_type == .ARM64_RELOC_GOT_LOAD_PAGEOFF12); |
| 440 | assert(rel.r_pcrel == 0); | 482 | assert(rel.r_pcrel == 0); |
| 441 | assert(rel.r_length == 2); | 483 | assert(rel.r_length == 2); |
| 442 | 484 | ||
| 443 | const offset = @intCast(u32, rel.r_address); | 485 | const target = try self.object.symbolFromReloc(rel); |
| 444 | const inst = parser.code[offset..][0..4]; | 486 | const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr); |
| 445 | assert(!isArithmeticOp(inst)); | 487 | assert(!isArithmeticOp(self.block.code[offset..][0..4])); |
| 446 | |||
| 447 | const parsed_inst = mem.bytesToValue(meta.TagPayload( | ||
| 448 | aarch64.Instruction, | ||
| 449 | aarch64.Instruction.load_store_register, | ||
| 450 | ), inst); | ||
| 451 | assert(parsed_inst.size == 3); | ||
| 452 | |||
| 453 | const target = Relocation.Target.fromReloc(rel); | ||
| 454 | 488 | ||
| 455 | var page_off = try parser.allocator.create(GotPageOff); | 489 | var page_off = try self.object.allocator.create(GotPageOff); |
| 456 | errdefer parser.allocator.destroy(page_off); | 490 | errdefer self.object.allocator.destroy(page_off); |
| 457 | 491 | ||
| 458 | page_off.* = .{ | 492 | page_off.* = .{ |
| 459 | .base = .{ | 493 | .base = .{ |
| 460 | .@"type" = .got_page_off, | 494 | .@"type" = .got_page_off, |
| 461 | .code = inst, | ||
| 462 | .offset = offset, | 495 | .offset = offset, |
| 463 | .target = target, | 496 | .target = target, |
| 464 | }, | 497 | .block = self.block, |
| 465 | .inst = .{ | ||
| 466 | .load_store_register = parsed_inst, | ||
| 467 | }, | 498 | }, |
| 468 | }; | 499 | }; |
| 469 | 500 | ||
| 470 | log.debug(" | emitting {}", .{page_off}); | 501 | return &page_off.base; |
| 471 | try parser.parsed.append(&page_off.base); | ||
| 472 | } | 502 | } |
| 473 | 503 | ||
| 474 | fn parseTlvpLoadPageOff(parser: *Parser, rel: macho.relocation_info) !void { | 504 | fn parseTlvpLoadPageOff(self: *Parser, rel: macho.relocation_info) !*Relocation { |
| 475 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); | 505 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); |
| 476 | assert(rel_type == .ARM64_RELOC_TLVP_LOAD_PAGEOFF12); | 506 | assert(rel_type == .ARM64_RELOC_TLVP_LOAD_PAGEOFF12); |
| 477 | assert(rel.r_pcrel == 0); | 507 | assert(rel.r_pcrel == 0); |
| ... | @@ -483,141 +513,102 @@ pub const Parser = struct { | ... | @@ -483,141 +513,102 @@ pub const Parser = struct { |
| 483 | size: u1, | 513 | size: u1, |
| 484 | }; | 514 | }; |
| 485 | 515 | ||
| 486 | const offset = @intCast(u32, rel.r_address); | 516 | const target = try self.object.symbolFromReloc(rel); |
| 487 | const inst = parser.code[offset..][0..4]; | 517 | const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr); |
| 488 | const parsed: RegInfo = parsed: { | ||
| 489 | if (isArithmeticOp(inst)) { | ||
| 490 | const parsed_inst = mem.bytesAsValue(meta.TagPayload( | ||
| 491 | aarch64.Instruction, | ||
| 492 | aarch64.Instruction.add_subtract_immediate, | ||
| 493 | ), inst); | ||
| 494 | break :parsed .{ | ||
| 495 | .rd = parsed_inst.rd, | ||
| 496 | .rn = parsed_inst.rn, | ||
| 497 | .size = parsed_inst.sf, | ||
| 498 | }; | ||
| 499 | } else { | ||
| 500 | const parsed_inst = mem.bytesAsValue(meta.TagPayload( | ||
| 501 | aarch64.Instruction, | ||
| 502 | aarch64.Instruction.load_store_register, | ||
| 503 | ), inst); | ||
| 504 | break :parsed .{ | ||
| 505 | .rd = parsed_inst.rt, | ||
| 506 | .rn = parsed_inst.rn, | ||
| 507 | .size = @truncate(u1, parsed_inst.size), | ||
| 508 | }; | ||
| 509 | } | ||
| 510 | }; | ||
| 511 | 518 | ||
| 512 | const target = Relocation.Target.fromReloc(rel); | 519 | var page_off = try self.object.allocator.create(TlvpPageOff); |
| 513 | 520 | errdefer self.object.allocator.destroy(page_off); | |
| 514 | var page_off = try parser.allocator.create(TlvpPageOff); | ||
| 515 | errdefer parser.allocator.destroy(page_off); | ||
| 516 | 521 | ||
| 517 | page_off.* = .{ | 522 | page_off.* = .{ |
| 518 | .base = .{ | 523 | .base = .{ |
| 519 | .@"type" = .tlvp_page_off, | 524 | .@"type" = .tlvp_page_off, |
| 520 | .code = inst, | ||
| 521 | .offset = offset, | 525 | .offset = offset, |
| 522 | .target = target, | 526 | .target = target, |
| 523 | }, | 527 | .block = self.block, |
| 524 | .inst = .{ | ||
| 525 | .add_subtract_immediate = .{ | ||
| 526 | .rd = parsed.rd, | ||
| 527 | .rn = parsed.rn, | ||
| 528 | .imm12 = 0, // This will be filled when target addresses are known. | ||
| 529 | .sh = 0, | ||
| 530 | .s = 0, | ||
| 531 | .op = 0, | ||
| 532 | .sf = parsed.size, | ||
| 533 | }, | ||
| 534 | }, | 528 | }, |
| 535 | }; | 529 | }; |
| 536 | 530 | ||
| 537 | log.debug(" | emitting {}", .{page_off}); | 531 | return &page_off.base; |
| 538 | try parser.parsed.append(&page_off.base); | ||
| 539 | } | 532 | } |
| 540 | 533 | ||
| 541 | fn parseSubtractor(parser: *Parser, rel: macho.relocation_info) !void { | 534 | fn parseSubtractor(self: *Parser, rel: macho.relocation_info) !void { |
| 542 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); | 535 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); |
| 543 | assert(rel_type == .ARM64_RELOC_SUBTRACTOR); | 536 | assert(rel_type == .ARM64_RELOC_SUBTRACTOR); |
| 544 | assert(rel.r_pcrel == 0); | 537 | assert(rel.r_pcrel == 0); |
| 545 | assert(parser.subtractor == null); | 538 | assert(self.subtractor == null); |
| 546 | 539 | ||
| 547 | parser.subtractor = Relocation.Target.fromReloc(rel); | 540 | self.subtractor = try self.object.symbolFromReloc(rel); |
| 548 | 541 | ||
| 549 | // Verify SUBTRACTOR is followed by UNSIGNED. | 542 | // Verify SUBTRACTOR is followed by UNSIGNED. |
| 550 | const next = @intToEnum(macho.reloc_type_arm64, parser.it.peek().r_type); | 543 | const next = @intToEnum(macho.reloc_type_arm64, self.it.peek().r_type); |
| 551 | if (next != .ARM64_RELOC_UNSIGNED) { | 544 | if (next != .ARM64_RELOC_UNSIGNED) { |
| 552 | log.err("unexpected relocation type: expected UNSIGNED, found {s}", .{next}); | 545 | log.err("unexpected relocation type: expected UNSIGNED, found {s}", .{next}); |
| 553 | return error.UnexpectedRelocationType; | 546 | return error.UnexpectedRelocationType; |
| 554 | } | 547 | } |
| 555 | } | 548 | } |
| 556 | 549 | ||
| 557 | fn parseUnsigned(parser: *Parser, rel: macho.relocation_info) !void { | 550 | fn parseUnsigned(self: *Parser, rel: macho.relocation_info) !*Relocation { |
| 558 | defer { | 551 | defer { |
| 559 | // Reset parser's subtractor state | 552 | // Reset parser's subtractor state |
| 560 | parser.subtractor = null; | 553 | self.subtractor = null; |
| 561 | } | 554 | } |
| 562 | 555 | ||
| 563 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); | 556 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); |
| 564 | assert(rel_type == .ARM64_RELOC_UNSIGNED); | 557 | assert(rel_type == .ARM64_RELOC_UNSIGNED); |
| 565 | assert(rel.r_pcrel == 0); | 558 | assert(rel.r_pcrel == 0); |
| 566 | 559 | ||
| 567 | var unsigned = try parser.allocator.create(reloc.Unsigned); | 560 | const target = try self.object.symbolFromReloc(rel); |
| 568 | errdefer parser.allocator.destroy(unsigned); | 561 | const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr); |
| 569 | |||
| 570 | const target = Relocation.Target.fromReloc(rel); | ||
| 571 | const is_64bit: bool = switch (rel.r_length) { | 562 | const is_64bit: bool = switch (rel.r_length) { |
| 572 | 3 => true, | 563 | 3 => true, |
| 573 | 2 => false, | 564 | 2 => false, |
| 574 | else => unreachable, | 565 | else => unreachable, |
| 575 | }; | 566 | }; |
| 576 | const offset = @intCast(u32, rel.r_address); | ||
| 577 | const addend: i64 = if (is_64bit) | 567 | const addend: i64 = if (is_64bit) |
| 578 | mem.readIntLittle(i64, parser.code[offset..][0..8]) | 568 | mem.readIntLittle(i64, self.block.code[offset..][0..8]) |
| 579 | else | 569 | else |
| 580 | mem.readIntLittle(i32, parser.code[offset..][0..4]); | 570 | mem.readIntLittle(i32, self.block.code[offset..][0..4]); |
| 571 | |||
| 572 | var unsigned = try self.object.allocator.create(reloc.Unsigned); | ||
| 573 | errdefer self.object.allocator.destroy(unsigned); | ||
| 581 | 574 | ||
| 582 | unsigned.* = .{ | 575 | unsigned.* = .{ |
| 583 | .base = .{ | 576 | .base = .{ |
| 584 | .@"type" = .unsigned, | 577 | .@"type" = .unsigned, |
| 585 | .code = if (is_64bit) parser.code[offset..][0..8] else parser.code[offset..][0..4], | ||
| 586 | .offset = offset, | 578 | .offset = offset, |
| 587 | .target = target, | 579 | .target = target, |
| 580 | .block = self.block, | ||
| 588 | }, | 581 | }, |
| 589 | .subtractor = parser.subtractor, | 582 | .subtractor = self.subtractor, |
| 590 | .is_64bit = is_64bit, | 583 | .is_64bit = is_64bit, |
| 591 | .addend = addend, | 584 | .addend = addend, |
| 592 | }; | 585 | }; |
| 593 | 586 | ||
| 594 | log.debug(" | emitting {}", .{unsigned}); | 587 | return &unsigned.base; |
| 595 | try parser.parsed.append(&unsigned.base); | ||
| 596 | } | 588 | } |
| 597 | 589 | ||
| 598 | fn parsePointerToGot(parser: *Parser, rel: macho.relocation_info) !void { | 590 | fn parsePointerToGot(self: *Parser, rel: macho.relocation_info) !*Relocation { |
| 599 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); | 591 | const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); |
| 600 | assert(rel_type == .ARM64_RELOC_POINTER_TO_GOT); | 592 | assert(rel_type == .ARM64_RELOC_POINTER_TO_GOT); |
| 601 | assert(rel.r_pcrel == 1); | 593 | assert(rel.r_pcrel == 1); |
| 602 | assert(rel.r_length == 2); | 594 | assert(rel.r_length == 2); |
| 603 | 595 | ||
| 604 | var ptr_to_got = try parser.allocator.create(PointerToGot); | 596 | var ptr_to_got = try self.object.allocator.create(PointerToGot); |
| 605 | errdefer parser.allocator.destroy(ptr_to_got); | 597 | errdefer self.object.allocator.destroy(ptr_to_got); |
| 606 | 598 | ||
| 607 | const target = Relocation.Target.fromReloc(rel); | 599 | const target = try self.object.symbolFromReloc(rel); |
| 608 | const offset = @intCast(u32, rel.r_address); | 600 | const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr); |
| 609 | 601 | ||
| 610 | ptr_to_got.* = .{ | 602 | ptr_to_got.* = .{ |
| 611 | .base = .{ | 603 | .base = .{ |
| 612 | .@"type" = .pointer_to_got, | 604 | .@"type" = .pointer_to_got, |
| 613 | .code = parser.code[offset..][0..4], | ||
| 614 | .offset = offset, | 605 | .offset = offset, |
| 615 | .target = target, | 606 | .target = target, |
| 607 | .block = self.block, | ||
| 616 | }, | 608 | }, |
| 617 | }; | 609 | }; |
| 618 | 610 | ||
| 619 | log.debug(" | emitting {}", .{ptr_to_got}); | 611 | return &ptr_to_got.base; |
| 620 | try parser.parsed.append(&ptr_to_got.base); | ||
| 621 | } | 612 | } |
| 622 | }; | 613 | }; |
| 623 | 614 |
src/link/MachO/reloc/x86_64.zig+182-140| ... | @@ -8,17 +8,28 @@ const meta = std.meta; | ... | @@ -8,17 +8,28 @@ const meta = std.meta; |
| 8 | const reloc = @import("../reloc.zig"); | 8 | const reloc = @import("../reloc.zig"); |
| 9 | 9 | ||
| 10 | const Allocator = mem.Allocator; | 10 | const Allocator = mem.Allocator; |
| 11 | const Object = @import("../Object.zig"); | ||
| 11 | const Relocation = reloc.Relocation; | 12 | const Relocation = reloc.Relocation; |
| 13 | const Symbol = @import("../Symbol.zig"); | ||
| 14 | const TextBlock = Zld.TextBlock; | ||
| 15 | const Zld = @import("../Zld.zig"); | ||
| 12 | 16 | ||
| 13 | pub const Branch = struct { | 17 | pub const Branch = struct { |
| 14 | base: Relocation, | 18 | base: Relocation, |
| 15 | 19 | ||
| 16 | pub const base_type: Relocation.Type = .branch_x86_64; | 20 | pub const base_type: Relocation.Type = .branch_x86_64; |
| 17 | 21 | ||
| 18 | pub fn resolve(branch: Branch, args: Relocation.ResolveArgs) !void { | 22 | // pub fn resolve(branch: Branch, args: Relocation.ResolveArgs) !void { |
| 19 | const displacement = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4); | 23 | // const displacement = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4); |
| 20 | log.debug(" | displacement 0x{x}", .{displacement}); | 24 | // log.debug(" | displacement 0x{x}", .{displacement}); |
| 21 | mem.writeIntLittle(u32, branch.base.code[0..4], @bitCast(u32, displacement)); | 25 | // mem.writeIntLittle(u32, branch.base.code[0..4], @bitCast(u32, displacement)); |
| 26 | // } | ||
| 27 | |||
| 28 | pub fn format(self: Branch, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | ||
| 29 | _ = self; | ||
| 30 | _ = fmt; | ||
| 31 | _ = options; | ||
| 32 | _ = writer; | ||
| 22 | } | 33 | } |
| 23 | }; | 34 | }; |
| 24 | 35 | ||
| ... | @@ -29,25 +40,32 @@ pub const Signed = struct { | ... | @@ -29,25 +40,32 @@ pub const Signed = struct { |
| 29 | 40 | ||
| 30 | pub const base_type: Relocation.Type = .signed; | 41 | pub const base_type: Relocation.Type = .signed; |
| 31 | 42 | ||
| 32 | pub fn resolve(signed: Signed, args: Relocation.ResolveArgs) !void { | 43 | // pub fn resolve(signed: Signed, args: Relocation.ResolveArgs) !void { |
| 33 | const target_addr = target_addr: { | 44 | // const target_addr = target_addr: { |
| 34 | if (signed.base.target == .section) { | 45 | // if (signed.base.target == .section) { |
| 35 | const source_target = @intCast(i64, args.source_source_sect_addr.?) + @intCast(i64, signed.base.offset) + signed.addend + 4; | 46 | // const source_target = @intCast(i64, args.source_source_sect_addr.?) + @intCast(i64, signed.base.offset) + signed.addend + 4; |
| 36 | const source_disp = source_target - @intCast(i64, args.source_target_sect_addr.?); | 47 | // const source_disp = source_target - @intCast(i64, args.source_target_sect_addr.?); |
| 37 | break :target_addr @intCast(i64, args.target_addr) + source_disp; | 48 | // break :target_addr @intCast(i64, args.target_addr) + source_disp; |
| 38 | } | 49 | // } |
| 39 | break :target_addr @intCast(i64, args.target_addr) + signed.addend; | 50 | // break :target_addr @intCast(i64, args.target_addr) + signed.addend; |
| 40 | }; | 51 | // }; |
| 41 | const displacement = try math.cast( | 52 | // const displacement = try math.cast( |
| 42 | i32, | 53 | // i32, |
| 43 | target_addr - @intCast(i64, args.source_addr) - signed.correction - 4, | 54 | // target_addr - @intCast(i64, args.source_addr) - signed.correction - 4, |
| 44 | ); | 55 | // ); |
| 45 | 56 | ||
| 46 | log.debug(" | addend 0x{x}", .{signed.addend}); | 57 | // log.debug(" | addend 0x{x}", .{signed.addend}); |
| 47 | log.debug(" | correction 0x{x}", .{signed.correction}); | 58 | // log.debug(" | correction 0x{x}", .{signed.correction}); |
| 48 | log.debug(" | displacement 0x{x}", .{displacement}); | 59 | // log.debug(" | displacement 0x{x}", .{displacement}); |
| 49 | 60 | ||
| 50 | mem.writeIntLittle(u32, signed.base.code[0..4], @bitCast(u32, displacement)); | 61 | // mem.writeIntLittle(u32, signed.base.code[0..4], @bitCast(u32, displacement)); |
| 62 | // } | ||
| 63 | |||
| 64 | pub fn format(self: Signed, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | ||
| 65 | _ = fmt; | ||
| 66 | _ = options; | ||
| 67 | try std.fmt.format(writer, ".addend = {}, ", .{self.addend}); | ||
| 68 | try std.fmt.format(writer, ".correction = {}, ", .{self.correction}); | ||
| 51 | } | 69 | } |
| 52 | }; | 70 | }; |
| 53 | 71 | ||
| ... | @@ -56,10 +74,17 @@ pub const GotLoad = struct { | ... | @@ -56,10 +74,17 @@ pub const GotLoad = struct { |
| 56 | 74 | ||
| 57 | pub const base_type: Relocation.Type = .got_load; | 75 | pub const base_type: Relocation.Type = .got_load; |
| 58 | 76 | ||
| 59 | pub fn resolve(got_load: GotLoad, args: Relocation.ResolveArgs) !void { | 77 | // pub fn resolve(got_load: GotLoad, args: Relocation.ResolveArgs) !void { |
| 60 | const displacement = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4); | 78 | // const displacement = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4); |
| 61 | log.debug(" | displacement 0x{x}", .{displacement}); | 79 | // log.debug(" | displacement 0x{x}", .{displacement}); |
| 62 | mem.writeIntLittle(u32, got_load.base.code[0..4], @bitCast(u32, displacement)); | 80 | // mem.writeIntLittle(u32, got_load.base.code[0..4], @bitCast(u32, displacement)); |
| 81 | // } | ||
| 82 | |||
| 83 | pub fn format(self: GotLoad, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | ||
| 84 | _ = self; | ||
| 85 | _ = fmt; | ||
| 86 | _ = options; | ||
| 87 | _ = writer; | ||
| 63 | } | 88 | } |
| 64 | }; | 89 | }; |
| 65 | 90 | ||
| ... | @@ -69,113 +94,139 @@ pub const Got = struct { | ... | @@ -69,113 +94,139 @@ pub const Got = struct { |
| 69 | 94 | ||
| 70 | pub const base_type: Relocation.Type = .got; | 95 | pub const base_type: Relocation.Type = .got; |
| 71 | 96 | ||
| 72 | pub fn resolve(got: Got, args: Relocation.ResolveArgs) !void { | 97 | // pub fn resolve(got: Got, args: Relocation.ResolveArgs) !void { |
| 73 | const displacement = try math.cast( | 98 | // const displacement = try math.cast( |
| 74 | i32, | 99 | // i32, |
| 75 | @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4 + got.addend, | 100 | // @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4 + got.addend, |
| 76 | ); | 101 | // ); |
| 77 | log.debug(" | displacement 0x{x}", .{displacement}); | 102 | // log.debug(" | displacement 0x{x}", .{displacement}); |
| 78 | mem.writeIntLittle(u32, got.base.code[0..4], @bitCast(u32, displacement)); | 103 | // mem.writeIntLittle(u32, got.base.code[0..4], @bitCast(u32, displacement)); |
| 104 | // } | ||
| 105 | |||
| 106 | pub fn format(self: Got, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | ||
| 107 | _ = fmt; | ||
| 108 | _ = options; | ||
| 109 | try std.fmt.format(writer, ".addend = {}, ", .{self.addend}); | ||
| 79 | } | 110 | } |
| 80 | }; | 111 | }; |
| 81 | 112 | ||
| 82 | pub const Tlv = struct { | 113 | pub const Tlv = struct { |
| 83 | base: Relocation, | 114 | base: Relocation, |
| 84 | op: *u8, | ||
| 85 | 115 | ||
| 86 | pub const base_type: Relocation.Type = .tlv; | 116 | pub const base_type: Relocation.Type = .tlv; |
| 87 | 117 | ||
| 88 | pub fn resolve(tlv: Tlv, args: Relocation.ResolveArgs) !void { | 118 | // pub fn resolve(tlv: Tlv, args: Relocation.ResolveArgs) !void { |
| 89 | // We need to rewrite the opcode from movq to leaq. | 119 | // // We need to rewrite the opcode from movq to leaq. |
| 90 | tlv.op.* = 0x8d; | 120 | // tlv.op.* = 0x8d; |
| 91 | log.debug(" | rewriting op to leaq", .{}); | 121 | // log.debug(" | rewriting op to leaq", .{}); |
| 92 | 122 | ||
| 93 | const displacement = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4); | 123 | // const displacement = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4); |
| 94 | log.debug(" | displacement 0x{x}", .{displacement}); | 124 | // log.debug(" | displacement 0x{x}", .{displacement}); |
| 95 | 125 | ||
| 96 | mem.writeIntLittle(u32, tlv.base.code[0..4], @bitCast(u32, displacement)); | 126 | // mem.writeIntLittle(u32, tlv.base.code[0..4], @bitCast(u32, displacement)); |
| 127 | // } | ||
| 128 | pub fn format(self: Tlv, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | ||
| 129 | _ = self; | ||
| 130 | _ = fmt; | ||
| 131 | _ = options; | ||
| 132 | _ = writer; | ||
| 97 | } | 133 | } |
| 98 | }; | 134 | }; |
| 99 | 135 | ||
| 100 | pub const Parser = struct { | 136 | pub const Parser = struct { |
| 101 | allocator: *Allocator, | 137 | object: *Object, |
| 138 | zld: *Zld, | ||
| 102 | it: *reloc.RelocIterator, | 139 | it: *reloc.RelocIterator, |
| 103 | code: []u8, | 140 | block: *TextBlock, |
| 104 | parsed: std.ArrayList(*Relocation), | 141 | base_addr: u64, |
| 105 | subtractor: ?Relocation.Target = null, | 142 | subtractor: ?*Symbol = null, |
| 106 | 143 | ||
| 107 | pub fn deinit(parser: *Parser) void { | 144 | pub fn parse(self: *Parser) !void { |
| 108 | parser.parsed.deinit(); | 145 | while (self.it.next()) |rel| { |
| 109 | } | 146 | const out_rel = switch (@intToEnum(macho.reloc_type_x86_64, rel.r_type)) { |
| 110 | 147 | .X86_64_RELOC_BRANCH => try self.parseBranch(rel), | |
| 111 | pub fn parse(parser: *Parser) !void { | ||
| 112 | while (parser.it.next()) |rel| { | ||
| 113 | switch (@intToEnum(macho.reloc_type_x86_64, rel.r_type)) { | ||
| 114 | .X86_64_RELOC_BRANCH => { | ||
| 115 | try parser.parseBranch(rel); | ||
| 116 | }, | ||
| 117 | .X86_64_RELOC_SUBTRACTOR => { | 148 | .X86_64_RELOC_SUBTRACTOR => { |
| 118 | try parser.parseSubtractor(rel); | 149 | // Subtractor is not a relocation with effect on the TextBlock, so |
| 119 | }, | 150 | // parse it and carry on. |
| 120 | .X86_64_RELOC_UNSIGNED => { | 151 | try self.parseSubtractor(rel); |
| 121 | try parser.parseUnsigned(rel); | 152 | continue; |
| 122 | }, | 153 | }, |
| 154 | .X86_64_RELOC_UNSIGNED => try self.parseUnsigned(rel), | ||
| 123 | .X86_64_RELOC_SIGNED, | 155 | .X86_64_RELOC_SIGNED, |
| 124 | .X86_64_RELOC_SIGNED_1, | 156 | .X86_64_RELOC_SIGNED_1, |
| 125 | .X86_64_RELOC_SIGNED_2, | 157 | .X86_64_RELOC_SIGNED_2, |
| 126 | .X86_64_RELOC_SIGNED_4, | 158 | .X86_64_RELOC_SIGNED_4, |
| 127 | => { | 159 | => try self.parseSigned(rel), |
| 128 | try parser.parseSigned(rel); | 160 | .X86_64_RELOC_GOT_LOAD => try self.parseGotLoad(rel), |
| 129 | }, | 161 | .X86_64_RELOC_GOT => try self.parseGot(rel), |
| 130 | .X86_64_RELOC_GOT_LOAD => { | 162 | .X86_64_RELOC_TLV => try self.parseTlv(rel), |
| 131 | try parser.parseGotLoad(rel); | 163 | }; |
| 132 | }, | 164 | try self.block.relocs.append(out_rel); |
| 133 | .X86_64_RELOC_GOT => { | 165 | |
| 134 | try parser.parseGot(rel); | 166 | if (out_rel.target.payload == .regular) { |
| 167 | try self.block.references.put(out_rel.target.payload.regular.local_sym_index, {}); | ||
| 168 | } | ||
| 169 | |||
| 170 | switch (out_rel.@"type") { | ||
| 171 | .got_load, .got => { | ||
| 172 | const sym = out_rel.target; | ||
| 173 | |||
| 174 | if (sym.got_index != null) continue; | ||
| 175 | |||
| 176 | const index = @intCast(u32, self.zld.got_entries.items.len); | ||
| 177 | sym.got_index = index; | ||
| 178 | try self.zld.got_entries.append(self.zld.allocator, sym); | ||
| 179 | |||
| 180 | log.debug("adding GOT entry for symbol {s} at index {}", .{ sym.name, index }); | ||
| 135 | }, | 181 | }, |
| 136 | .X86_64_RELOC_TLV => { | 182 | .branch_x86_64 => { |
| 137 | try parser.parseTlv(rel); | 183 | const sym = out_rel.target; |
| 184 | |||
| 185 | if (sym.stubs_index != null) continue; | ||
| 186 | if (sym.payload != .proxy) continue; | ||
| 187 | |||
| 188 | const index = @intCast(u32, self.zld.stubs.items.len); | ||
| 189 | sym.stubs_index = index; | ||
| 190 | try self.zld.stubs.append(self.zld.allocator, sym); | ||
| 191 | |||
| 192 | log.debug("adding stub entry for symbol {s} at index {}", .{ sym.name, index }); | ||
| 138 | }, | 193 | }, |
| 194 | else => {}, | ||
| 139 | } | 195 | } |
| 140 | } | 196 | } |
| 141 | } | 197 | } |
| 142 | 198 | ||
| 143 | fn parseBranch(parser: *Parser, rel: macho.relocation_info) !void { | 199 | fn parseBranch(self: *Parser, rel: macho.relocation_info) !*Relocation { |
| 144 | const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type); | 200 | const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type); |
| 145 | assert(rel_type == .X86_64_RELOC_BRANCH); | 201 | assert(rel_type == .X86_64_RELOC_BRANCH); |
| 146 | assert(rel.r_pcrel == 1); | 202 | assert(rel.r_pcrel == 1); |
| 147 | assert(rel.r_length == 2); | 203 | assert(rel.r_length == 2); |
| 148 | 204 | ||
| 149 | const offset = @intCast(u32, rel.r_address); | 205 | const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr); |
| 150 | const inst = parser.code[offset..][0..4]; | 206 | const target = try self.object.symbolFromReloc(rel); |
| 151 | |||
| 152 | var branch = try parser.allocator.create(Branch); | ||
| 153 | errdefer parser.allocator.destroy(branch); | ||
| 154 | 207 | ||
| 155 | const target = Relocation.Target.fromReloc(rel); | 208 | var branch = try self.object.allocator.create(Branch); |
| 209 | errdefer self.object.allocator.destroy(branch); | ||
| 156 | 210 | ||
| 157 | branch.* = .{ | 211 | branch.* = .{ |
| 158 | .base = .{ | 212 | .base = .{ |
| 159 | .@"type" = .branch_x86_64, | 213 | .@"type" = .branch_x86_64, |
| 160 | .code = inst, | ||
| 161 | .offset = offset, | 214 | .offset = offset, |
| 162 | .target = target, | 215 | .target = target, |
| 216 | .block = self.block, | ||
| 163 | }, | 217 | }, |
| 164 | }; | 218 | }; |
| 165 | 219 | ||
| 166 | log.debug(" | emitting {}", .{branch}); | 220 | return &branch.base; |
| 167 | try parser.parsed.append(&branch.base); | ||
| 168 | } | 221 | } |
| 169 | 222 | ||
| 170 | fn parseSigned(parser: *Parser, rel: macho.relocation_info) !void { | 223 | fn parseSigned(self: *Parser, rel: macho.relocation_info) !*Relocation { |
| 171 | assert(rel.r_pcrel == 1); | 224 | assert(rel.r_pcrel == 1); |
| 172 | assert(rel.r_length == 2); | 225 | assert(rel.r_length == 2); |
| 173 | 226 | ||
| 174 | const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type); | 227 | const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type); |
| 175 | const target = Relocation.Target.fromReloc(rel); | 228 | const target = try self.object.symbolFromReloc(rel); |
| 176 | 229 | const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr); | |
| 177 | const offset = @intCast(u32, rel.r_address); | ||
| 178 | const inst = parser.code[offset..][0..4]; | ||
| 179 | const correction: i4 = switch (rel_type) { | 230 | const correction: i4 = switch (rel_type) { |
| 180 | .X86_64_RELOC_SIGNED => 0, | 231 | .X86_64_RELOC_SIGNED => 0, |
| 181 | .X86_64_RELOC_SIGNED_1 => 1, | 232 | .X86_64_RELOC_SIGNED_1 => 1, |
| ... | @@ -183,161 +234,152 @@ pub const Parser = struct { | ... | @@ -183,161 +234,152 @@ pub const Parser = struct { |
| 183 | .X86_64_RELOC_SIGNED_4 => 4, | 234 | .X86_64_RELOC_SIGNED_4 => 4, |
| 184 | else => unreachable, | 235 | else => unreachable, |
| 185 | }; | 236 | }; |
| 186 | const addend = mem.readIntLittle(i32, inst) + correction; | 237 | const addend = mem.readIntLittle(i32, self.block.code[offset..][0..4]) + correction; |
| 187 | 238 | ||
| 188 | var signed = try parser.allocator.create(Signed); | 239 | var signed = try self.object.allocator.create(Signed); |
| 189 | errdefer parser.allocator.destroy(signed); | 240 | errdefer self.object.allocator.destroy(signed); |
| 190 | 241 | ||
| 191 | signed.* = .{ | 242 | signed.* = .{ |
| 192 | .base = .{ | 243 | .base = .{ |
| 193 | .@"type" = .signed, | 244 | .@"type" = .signed, |
| 194 | .code = inst, | ||
| 195 | .offset = offset, | 245 | .offset = offset, |
| 196 | .target = target, | 246 | .target = target, |
| 247 | .block = self.block, | ||
| 197 | }, | 248 | }, |
| 198 | .addend = addend, | 249 | .addend = addend, |
| 199 | .correction = correction, | 250 | .correction = correction, |
| 200 | }; | 251 | }; |
| 201 | 252 | ||
| 202 | log.debug(" | emitting {}", .{signed}); | 253 | return &signed.base; |
| 203 | try parser.parsed.append(&signed.base); | ||
| 204 | } | 254 | } |
| 205 | 255 | ||
| 206 | fn parseGotLoad(parser: *Parser, rel: macho.relocation_info) !void { | 256 | fn parseGotLoad(self: *Parser, rel: macho.relocation_info) !*Relocation { |
| 207 | const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type); | 257 | const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type); |
| 208 | assert(rel_type == .X86_64_RELOC_GOT_LOAD); | 258 | assert(rel_type == .X86_64_RELOC_GOT_LOAD); |
| 209 | assert(rel.r_pcrel == 1); | 259 | assert(rel.r_pcrel == 1); |
| 210 | assert(rel.r_length == 2); | 260 | assert(rel.r_length == 2); |
| 211 | 261 | ||
| 212 | const offset = @intCast(u32, rel.r_address); | 262 | const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr); |
| 213 | const inst = parser.code[offset..][0..4]; | 263 | const target = try self.object.symbolFromReloc(rel); |
| 214 | const target = Relocation.Target.fromReloc(rel); | ||
| 215 | 264 | ||
| 216 | var got_load = try parser.allocator.create(GotLoad); | 265 | var got_load = try self.object.allocator.create(GotLoad); |
| 217 | errdefer parser.allocator.destroy(got_load); | 266 | errdefer self.object.allocator.destroy(got_load); |
| 218 | 267 | ||
| 219 | got_load.* = .{ | 268 | got_load.* = .{ |
| 220 | .base = .{ | 269 | .base = .{ |
| 221 | .@"type" = .got_load, | 270 | .@"type" = .got_load, |
| 222 | .code = inst, | ||
| 223 | .offset = offset, | 271 | .offset = offset, |
| 224 | .target = target, | 272 | .target = target, |
| 273 | .block = self.block, | ||
| 225 | }, | 274 | }, |
| 226 | }; | 275 | }; |
| 227 | 276 | ||
| 228 | log.debug(" | emitting {}", .{got_load}); | 277 | return &got_load.base; |
| 229 | try parser.parsed.append(&got_load.base); | ||
| 230 | } | 278 | } |
| 231 | 279 | ||
| 232 | fn parseGot(parser: *Parser, rel: macho.relocation_info) !void { | 280 | fn parseGot(self: *Parser, rel: macho.relocation_info) !*Relocation { |
| 233 | const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type); | 281 | const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type); |
| 234 | assert(rel_type == .X86_64_RELOC_GOT); | 282 | assert(rel_type == .X86_64_RELOC_GOT); |
| 235 | assert(rel.r_pcrel == 1); | 283 | assert(rel.r_pcrel == 1); |
| 236 | assert(rel.r_length == 2); | 284 | assert(rel.r_length == 2); |
| 237 | 285 | ||
| 238 | const offset = @intCast(u32, rel.r_address); | 286 | const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr); |
| 239 | const inst = parser.code[offset..][0..4]; | 287 | const target = try self.object.symbolFromReloc(rel); |
| 240 | const target = Relocation.Target.fromReloc(rel); | 288 | const addend = mem.readIntLittle(i32, self.block.code[offset..][0..4]); |
| 241 | const addend = mem.readIntLittle(i32, inst); | ||
| 242 | 289 | ||
| 243 | var got = try parser.allocator.create(Got); | 290 | var got = try self.object.allocator.create(Got); |
| 244 | errdefer parser.allocator.destroy(got); | 291 | errdefer self.object.allocator.destroy(got); |
| 245 | 292 | ||
| 246 | got.* = .{ | 293 | got.* = .{ |
| 247 | .base = .{ | 294 | .base = .{ |
| 248 | .@"type" = .got, | 295 | .@"type" = .got, |
| 249 | .code = inst, | ||
| 250 | .offset = offset, | 296 | .offset = offset, |
| 251 | .target = target, | 297 | .target = target, |
| 298 | .block = self.block, | ||
| 252 | }, | 299 | }, |
| 253 | .addend = addend, | 300 | .addend = addend, |
| 254 | }; | 301 | }; |
| 255 | 302 | ||
| 256 | log.debug(" | emitting {}", .{got}); | 303 | return &got.base; |
| 257 | try parser.parsed.append(&got.base); | ||
| 258 | } | 304 | } |
| 259 | 305 | ||
| 260 | fn parseTlv(parser: *Parser, rel: macho.relocation_info) !void { | 306 | fn parseTlv(self: *Parser, rel: macho.relocation_info) !*Relocation { |
| 261 | const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type); | 307 | const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type); |
| 262 | assert(rel_type == .X86_64_RELOC_TLV); | 308 | assert(rel_type == .X86_64_RELOC_TLV); |
| 263 | assert(rel.r_pcrel == 1); | 309 | assert(rel.r_pcrel == 1); |
| 264 | assert(rel.r_length == 2); | 310 | assert(rel.r_length == 2); |
| 265 | 311 | ||
| 266 | const offset = @intCast(u32, rel.r_address); | 312 | const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr); |
| 267 | const inst = parser.code[offset..][0..4]; | 313 | const target = try self.object.symbolFromReloc(rel); |
| 268 | const target = Relocation.Target.fromReloc(rel); | ||
| 269 | 314 | ||
| 270 | var tlv = try parser.allocator.create(Tlv); | 315 | var tlv = try self.object.allocator.create(Tlv); |
| 271 | errdefer parser.allocator.destroy(tlv); | 316 | errdefer self.object.allocator.destroy(tlv); |
| 272 | 317 | ||
| 273 | tlv.* = .{ | 318 | tlv.* = .{ |
| 274 | .base = .{ | 319 | .base = .{ |
| 275 | .@"type" = .tlv, | 320 | .@"type" = .tlv, |
| 276 | .code = inst, | ||
| 277 | .offset = offset, | 321 | .offset = offset, |
| 278 | .target = target, | 322 | .target = target, |
| 323 | .block = self.block, | ||
| 279 | }, | 324 | }, |
| 280 | .op = &parser.code[offset - 2], | ||
| 281 | }; | 325 | }; |
| 282 | 326 | ||
| 283 | log.debug(" | emitting {}", .{tlv}); | 327 | return &tlv.base; |
| 284 | try parser.parsed.append(&tlv.base); | ||
| 285 | } | 328 | } |
| 286 | 329 | ||
| 287 | fn parseSubtractor(parser: *Parser, rel: macho.relocation_info) !void { | 330 | fn parseSubtractor(self: *Parser, rel: macho.relocation_info) !void { |
| 288 | const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type); | 331 | const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type); |
| 289 | assert(rel_type == .X86_64_RELOC_SUBTRACTOR); | 332 | assert(rel_type == .X86_64_RELOC_SUBTRACTOR); |
| 290 | assert(rel.r_pcrel == 0); | 333 | assert(rel.r_pcrel == 0); |
| 291 | assert(parser.subtractor == null); | 334 | assert(self.subtractor == null); |
| 292 | 335 | ||
| 293 | parser.subtractor = Relocation.Target.fromReloc(rel); | 336 | self.subtractor = try self.object.symbolFromReloc(rel); |
| 294 | 337 | ||
| 295 | // Verify SUBTRACTOR is followed by UNSIGNED. | 338 | // Verify SUBTRACTOR is followed by UNSIGNED. |
| 296 | const next = @intToEnum(macho.reloc_type_x86_64, parser.it.peek().r_type); | 339 | const next = @intToEnum(macho.reloc_type_x86_64, self.it.peek().r_type); |
| 297 | if (next != .X86_64_RELOC_UNSIGNED) { | 340 | if (next != .X86_64_RELOC_UNSIGNED) { |
| 298 | log.err("unexpected relocation type: expected UNSIGNED, found {s}", .{next}); | 341 | log.err("unexpected relocation type: expected UNSIGNED, found {s}", .{next}); |
| 299 | return error.UnexpectedRelocationType; | 342 | return error.UnexpectedRelocationType; |
| 300 | } | 343 | } |
| 301 | } | 344 | } |
| 302 | 345 | ||
| 303 | fn parseUnsigned(parser: *Parser, rel: macho.relocation_info) !void { | 346 | fn parseUnsigned(self: *Parser, rel: macho.relocation_info) !*Relocation { |
| 304 | defer { | 347 | defer { |
| 305 | // Reset parser's subtractor state | 348 | // Reset parser's subtractor state |
| 306 | parser.subtractor = null; | 349 | self.subtractor = null; |
| 307 | } | 350 | } |
| 308 | 351 | ||
| 309 | const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type); | 352 | const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type); |
| 310 | assert(rel_type == .X86_64_RELOC_UNSIGNED); | 353 | assert(rel_type == .X86_64_RELOC_UNSIGNED); |
| 311 | assert(rel.r_pcrel == 0); | 354 | assert(rel.r_pcrel == 0); |
| 312 | 355 | ||
| 313 | var unsigned = try parser.allocator.create(reloc.Unsigned); | 356 | const target = try self.object.symbolFromReloc(rel); |
| 314 | errdefer parser.allocator.destroy(unsigned); | ||
| 315 | |||
| 316 | const target = Relocation.Target.fromReloc(rel); | ||
| 317 | const is_64bit: bool = switch (rel.r_length) { | 357 | const is_64bit: bool = switch (rel.r_length) { |
| 318 | 3 => true, | 358 | 3 => true, |
| 319 | 2 => false, | 359 | 2 => false, |
| 320 | else => unreachable, | 360 | else => unreachable, |
| 321 | }; | 361 | }; |
| 322 | const offset = @intCast(u32, rel.r_address); | 362 | const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr); |
| 323 | const addend: i64 = if (is_64bit) | 363 | const addend: i64 = if (is_64bit) |
| 324 | mem.readIntLittle(i64, parser.code[offset..][0..8]) | 364 | mem.readIntLittle(i64, self.block.code[offset..][0..8]) |
| 325 | else | 365 | else |
| 326 | mem.readIntLittle(i32, parser.code[offset..][0..4]); | 366 | mem.readIntLittle(i32, self.block.code[offset..][0..4]); |
| 367 | |||
| 368 | var unsigned = try self.object.allocator.create(reloc.Unsigned); | ||
| 369 | errdefer self.object.allocator.destroy(unsigned); | ||
| 327 | 370 | ||
| 328 | unsigned.* = .{ | 371 | unsigned.* = .{ |
| 329 | .base = .{ | 372 | .base = .{ |
| 330 | .@"type" = .unsigned, | 373 | .@"type" = .unsigned, |
| 331 | .code = if (is_64bit) parser.code[offset..][0..8] else parser.code[offset..][0..4], | ||
| 332 | .offset = offset, | 374 | .offset = offset, |
| 333 | .target = target, | 375 | .target = target, |
| 376 | .block = self.block, | ||
| 334 | }, | 377 | }, |
| 335 | .subtractor = parser.subtractor, | 378 | .subtractor = self.subtractor, |
| 336 | .is_64bit = is_64bit, | 379 | .is_64bit = is_64bit, |
| 337 | .addend = addend, | 380 | .addend = addend, |
| 338 | }; | 381 | }; |
| 339 | 382 | ||
| 340 | log.debug(" | emitting {}", .{unsigned}); | 383 | return &unsigned.base; |
| 341 | try parser.parsed.append(&unsigned.base); | ||
| 342 | } | 384 | } |
| 343 | }; | 385 | }; |