| ... | @@ -252,9 +252,9 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { | ... | @@ -252,9 +252,9 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { |
| 252 | try self.populateMetadata(); | 252 | try self.populateMetadata(); |
| 253 | try self.parseInputFiles(files); | 253 | try self.parseInputFiles(files); |
| 254 | try self.resolveImports(); | 254 | try self.resolveImports(); |
| 255 | try self.allocateTextSegment(); | 255 | self.allocateTextSegment(); |
| 256 | try self.allocateDataSegment(); | 256 | self.allocateDataSegment(); |
| 257 | try self.allocateLinkeditSegment(); | 257 | self.allocateLinkeditSegment(); |
| 258 | try self.writeStubHelperCommon(); | 258 | try self.writeStubHelperCommon(); |
| 259 | try self.resolveSymbols(); | 259 | try self.resolveSymbols(); |
| 260 | try self.doRelocs(); | 260 | try self.doRelocs(); |
| ... | @@ -317,20 +317,13 @@ fn parseObjectFile(self: *Zld, object: *const Object) !void { | ... | @@ -317,20 +317,13 @@ fn parseObjectFile(self: *Zld, object: *const Object) !void { |
| 317 | if (mem.eql(u8, sectname, "__thread_vars")) { | 317 | if (mem.eql(u8, sectname, "__thread_vars")) { |
| 318 | self.tlv_section_index = sect_index; | 318 | self.tlv_section_index = sect_index; |
| 319 | } | 319 | } |
| 320 | log.warn("{s} align 0x{x}", .{ sectname, sect.@"align" }); | | |
| 321 | const alignment = switch (sect.flags) { | | |
| 322 | macho.S_4BYTE_LITERALS => 2, | | |
| 323 | macho.S_8BYTE_LITERALS => 3, | | |
| 324 | macho.S_16BYTE_LITERALS => 4, | | |
| 325 | else => sect.@"align", | | |
| 326 | }; | | |
| 327 | try seg.append(self.allocator, .{ | 320 | try seg.append(self.allocator, .{ |
| 328 | .sectname = makeStaticString(&sect.sectname), | 321 | .sectname = makeStaticString(&sect.sectname), |
| 329 | .segname = makeStaticString(&sect.segname), | 322 | .segname = makeStaticString(&sect.segname), |
| 330 | .addr = 0, | 323 | .addr = 0, |
| 331 | .size = 0, | 324 | .size = 0, |
| 332 | .offset = 0, | 325 | .offset = 0, |
| 333 | .@"align" = alignment, | 326 | .@"align" = sect.@"align", |
| 334 | .reloff = 0, | 327 | .reloff = 0, |
| 335 | .nreloc = 0, | 328 | .nreloc = 0, |
| 336 | .flags = sect.flags, | 329 | .flags = sect.flags, |
| ... | @@ -436,7 +429,7 @@ fn resolveImports(self: *Zld) !void { | ... | @@ -436,7 +429,7 @@ fn resolveImports(self: *Zld) !void { |
| 436 | }); | 429 | }); |
| 437 | } | 430 | } |
| 438 | | 431 | |
| 439 | fn allocateTextSegment(self: *Zld) !void { | 432 | fn allocateTextSegment(self: *Zld) void { |
| 440 | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 433 | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 441 | const nexterns = @intCast(u32, self.lazy_imports.items().len); | 434 | const nexterns = @intCast(u32, self.lazy_imports.items().len); |
| 442 | | 435 | |
| ... | @@ -457,7 +450,7 @@ fn allocateTextSegment(self: *Zld) !void { | ... | @@ -457,7 +450,7 @@ fn allocateTextSegment(self: *Zld) !void { |
| 457 | sizeofcmds += lc.cmdsize(); | 450 | sizeofcmds += lc.cmdsize(); |
| 458 | } | 451 | } |
| 459 | | 452 | |
| 460 | try self.allocateSegment( | 453 | self.allocateSegment( |
| 461 | self.text_segment_cmd_index.?, | 454 | self.text_segment_cmd_index.?, |
| 462 | 0, | 455 | 0, |
| 463 | sizeofcmds, | 456 | sizeofcmds, |
| ... | @@ -465,7 +458,7 @@ fn allocateTextSegment(self: *Zld) !void { | ... | @@ -465,7 +458,7 @@ fn allocateTextSegment(self: *Zld) !void { |
| 465 | ); | 458 | ); |
| 466 | } | 459 | } |
| 467 | | 460 | |
| 468 | fn allocateDataSegment(self: *Zld) !void { | 461 | fn allocateDataSegment(self: *Zld) void { |
| 469 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 462 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 470 | const nonlazy = @intCast(u32, self.nonlazy_imports.items().len); | 463 | const nonlazy = @intCast(u32, self.nonlazy_imports.items().len); |
| 471 | const lazy = @intCast(u32, self.lazy_imports.items().len); | 464 | const lazy = @intCast(u32, self.lazy_imports.items().len); |
| ... | @@ -482,16 +475,16 @@ fn allocateDataSegment(self: *Zld) !void { | ... | @@ -482,16 +475,16 @@ fn allocateDataSegment(self: *Zld) !void { |
| 482 | | 475 | |
| 483 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 476 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 484 | const offset = text_seg.inner.fileoff + text_seg.inner.filesize; | 477 | const offset = text_seg.inner.fileoff + text_seg.inner.filesize; |
| 485 | try self.allocateSegment(self.data_segment_cmd_index.?, offset, 0, false); | 478 | self.allocateSegment(self.data_segment_cmd_index.?, offset, 0, false); |
| 486 | } | 479 | } |
| 487 | | 480 | |
| 488 | fn allocateLinkeditSegment(self: *Zld) !void { | 481 | fn allocateLinkeditSegment(self: *Zld) void { |
| 489 | const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 482 | const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 490 | const offset = data_seg.inner.fileoff + data_seg.inner.filesize; | 483 | const offset = data_seg.inner.fileoff + data_seg.inner.filesize; |
| 491 | try self.allocateSegment(self.linkedit_segment_cmd_index.?, offset, 0, false); | 484 | self.allocateSegment(self.linkedit_segment_cmd_index.?, offset, 0, false); |
| 492 | } | 485 | } |
| 493 | | 486 | |
| 494 | fn allocateSegment(self: *Zld, index: u16, offset: u64, start: u64, reverse: bool) !void { | 487 | fn allocateSegment(self: *Zld, index: u16, offset: u64, start: u64, reverse: bool) void { |
| 495 | const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize; | 488 | const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize; |
| 496 | const seg = &self.load_commands.items[index].Segment; | 489 | const seg = &self.load_commands.items[index].Segment; |
| 497 | | 490 | |
| ... | @@ -565,39 +558,72 @@ fn writeStubHelperCommon(self: *Zld) !void { | ... | @@ -565,39 +558,72 @@ fn writeStubHelperCommon(self: *Zld) !void { |
| 565 | }, | 558 | }, |
| 566 | .aarch64 => { | 559 | .aarch64 => { |
| 567 | var code: [6 * @sizeOf(u32)]u8 = undefined; | 560 | var code: [6 * @sizeOf(u32)]u8 = undefined; |
| 568 | { | 561 | data_blk_outer: { |
| | 562 | const this_addr = stub_helper.addr; |
| 569 | const target_addr = data.addr + data.size - @sizeOf(u64); | 563 | const target_addr = data.addr + data.size - @sizeOf(u64); |
| 570 | const displacement = @bitCast(u21, try math.cast(i21, target_addr - stub_helper.addr)); | 564 | data_blk: { |
| 571 | // adr x17, disp | 565 | const displacement = math.cast(i21, target_addr - this_addr) catch |_| break :data_blk; |
| 572 | mem.writeIntLittle(u32, code[0..4], Arm64.adr(17, displacement).toU32()); | 566 | // adr x17, disp |
| 573 | // TODO check if adr is enough and expand into adrp + add if not. | 567 | mem.writeIntLittle(u32, code[0..4], Arm64.adr(17, @bitCast(u21, displacement)).toU32()); |
| 574 | // nop in case we need to expand adr for adrp followed by add. | 568 | // nop |
| 575 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32()); | 569 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32()); |
| | 570 | break :data_blk_outer; |
| | 571 | } |
| | 572 | data_blk: { |
| | 573 | const new_this_addr = this_addr + @sizeOf(u32); |
| | 574 | const displacement = math.cast(i21, target_addr - new_this_addr) catch |_| break :data_blk; |
| | 575 | // nop |
| | 576 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32()); |
| | 577 | // adr x17, disp |
| | 578 | mem.writeIntLittle(u32, code[4..8], Arm64.adr(17, @bitCast(u21, displacement)).toU32()); |
| | 579 | break :data_blk_outer; |
| | 580 | } |
| | 581 | // Jump is too big, replace adr with adrp and add. |
| | 582 | const this_page = @intCast(i32, this_addr >> 12); |
| | 583 | const target_page = @intCast(i32, target_addr >> 12); |
| | 584 | const pages = @bitCast(u21, @intCast(i21, target_page - this_page)); |
| | 585 | mem.writeIntLittle(u32, code[0..4], Arm64.adrp(17, pages).toU32()); |
| | 586 | const narrowed = @truncate(u12, target_addr); |
| | 587 | mem.writeIntLittle(u32, code[4..8], Arm64.add(17, 17, narrowed, 1).toU32()); |
| 576 | } | 588 | } |
| 577 | // stp x16, x17, [sp, #-16]! | 589 | // stp x16, x17, [sp, #-16]! |
| 578 | code[8] = 0xf0; | 590 | code[8] = 0xf0; |
| 579 | code[9] = 0x47; | 591 | code[9] = 0x47; |
| 580 | code[10] = 0xbf; | 592 | code[10] = 0xbf; |
| 581 | code[11] = 0xa9; | 593 | code[11] = 0xa9; |
| 582 | binder: { | 594 | binder_blk_outer: { |
| 583 | const dyld_stub_binder = self.nonlazy_imports.get("dyld_stub_binder").?; | 595 | const dyld_stub_binder = self.nonlazy_imports.get("dyld_stub_binder").?; |
| 584 | const addr = (got.addr + dyld_stub_binder.index * @sizeOf(u64)); | 596 | const this_addr = stub_helper.addr + 3 * @sizeOf(u32); |
| 585 | const displacement = math.divExact(u64, addr - stub_helper.addr - 3 * @sizeOf(u32), 4) catch |_| { | 597 | const target_addr = (got.addr + dyld_stub_binder.index * @sizeOf(u64)); |
| 586 | log.warn("0x{x}", .{addr - stub_helper.addr - 3 * @sizeOf(u32)}); | 598 | binder_blk: { |
| | 599 | const displacement = math.divExact(u64, target_addr - this_addr, 4) catch |_| break :binder_blk; |
| | 600 | const literal = math.cast(u18, displacement) catch |_| break :binder_blk; |
| | 601 | // ldr x16, label |
| | 602 | mem.writeIntLittle(u32, code[12..16], Arm64.ldr(16, literal, 1).toU32()); |
| | 603 | // nop |
| | 604 | mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.nop().toU32()); |
| | 605 | break :binder_blk_outer; |
| | 606 | } |
| | 607 | binder_blk: { |
| | 608 | const new_this_addr = this_addr + @sizeOf(u32); |
| | 609 | const displacement = math.divExact(u64, target_addr - new_this_addr, 4) catch |_| break :binder_blk; |
| | 610 | const literal = math.cast(u18, displacement) catch |_| break :binder_blk; |
| | 611 | log.warn("2: disp=0x{x}, literal=0x{x}", .{ displacement, literal }); |
| 587 | // Pad with nop to please division. | 612 | // Pad with nop to please division. |
| 588 | // nop | 613 | // nop |
| 589 | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.nop().toU32()); | 614 | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.nop().toU32()); |
| 590 | // ldr x16, label | 615 | // ldr x16, label |
| 591 | const disp = try math.divExact(u64, addr - stub_helper.addr - 4 * @sizeOf(u32), 4); | | |
| 592 | const literal = try math.cast(u19, disp); // TODO use adrp + add if we exceed the range. | | |
| 593 | mem.writeIntLittle(u32, code[16..20], Arm64.ldr(16, literal, 1).toU32()); | 616 | mem.writeIntLittle(u32, code[16..20], Arm64.ldr(16, literal, 1).toU32()); |
| 594 | break :binder; | 617 | break :binder_blk_outer; |
| 595 | }; | 618 | } |
| 596 | const literal = try math.cast(u19, displacement); // TODO use adrp + add if we exceed the range. | 619 | // Use adrp followed by ldr(immediate). |
| 597 | // ldr x16, label | 620 | const this_page = @intCast(i32, this_addr >> 12); |
| 598 | mem.writeIntLittle(u32, code[12..16], Arm64.ldr(16, literal, 1).toU32()); | 621 | const target_page = @intCast(i32, target_addr >> 12); |
| 599 | // nop | 622 | const pages = @bitCast(u21, @intCast(i21, target_page - this_page)); |
| 600 | mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.nop().toU32()); | 623 | mem.writeIntLittle(u32, code[12..16], Arm64.adrp(16, pages).toU32()); |
| | 624 | const narrowed = @truncate(u12, target_addr); |
| | 625 | const offset = try math.divExact(u12, narrowed, 8); |
| | 626 | mem.writeIntLittle(u32, code[16..20], Arm64.ldrq(16, 16, offset).toU32()); |
| 601 | } | 627 | } |
| 602 | // br x16 | 628 | // br x16 |
| 603 | code[20] = 0x00; | 629 | code[20] = 0x00; |
| ... | @@ -662,12 +688,37 @@ fn writeStub(self: *Zld, index: u32) !void { | ... | @@ -662,12 +688,37 @@ fn writeStub(self: *Zld, index: u32) !void { |
| 662 | }, | 688 | }, |
| 663 | .aarch64 => { | 689 | .aarch64 => { |
| 664 | assert(la_ptr_addr >= stub_addr); | 690 | assert(la_ptr_addr >= stub_addr); |
| 665 | const displacement = try math.divExact(u64, la_ptr_addr - stub_addr - @sizeOf(u32), 4); | 691 | outer: { |
| 666 | const literal = try math.cast(u19, displacement); | 692 | const this_addr = stub_addr; |
| 667 | // nop | 693 | const target_addr = la_ptr_addr; |
| 668 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32()); | 694 | inner: { |
| 669 | // ldr x16, literal | 695 | const displacement = math.divExact(u64, target_addr - this_addr, 4) catch |_| break :inner; |
| 670 | mem.writeIntLittle(u32, code[4..8], Arm64.ldr(16, literal, 1).toU32()); | 696 | const literal = math.cast(u18, displacement) catch |_| break :inner; |
| | 697 | // ldr x16, literal |
| | 698 | mem.writeIntLittle(u32, code[0..4], Arm64.ldr(16, literal, 1).toU32()); |
| | 699 | // nop |
| | 700 | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32()); |
| | 701 | break :outer; |
| | 702 | } |
| | 703 | inner: { |
| | 704 | const new_this_addr = this_addr + @sizeOf(u32); |
| | 705 | const displacement = math.divExact(u64, target_addr - new_this_addr, 4) catch |_| break :inner; |
| | 706 | const literal = math.cast(u18, displacement) catch |_| break :inner; |
| | 707 | // nop |
| | 708 | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32()); |
| | 709 | // ldr x16, literal |
| | 710 | mem.writeIntLittle(u32, code[4..8], Arm64.ldr(16, literal, 1).toU32()); |
| | 711 | break :outer; |
| | 712 | } |
| | 713 | // Use adrp followed by ldr(immediate). |
| | 714 | const this_page = @intCast(i32, this_addr >> 12); |
| | 715 | const target_page = @intCast(i32, target_addr >> 12); |
| | 716 | const pages = @bitCast(u21, @intCast(i21, target_page - this_page)); |
| | 717 | mem.writeIntLittle(u32, code[0..4], Arm64.adrp(16, pages).toU32()); |
| | 718 | const narrowed = @truncate(u12, target_addr); |
| | 719 | const offset = try math.divExact(u12, narrowed, 8); |
| | 720 | mem.writeIntLittle(u32, code[4..8], Arm64.ldrq(16, 16, offset).toU32()); |
| | 721 | } |
| 671 | // br x16 | 722 | // br x16 |
| 672 | mem.writeIntLittle(u32, code[8..12], Arm64.br(16).toU32()); | 723 | mem.writeIntLittle(u32, code[8..12], Arm64.br(16).toU32()); |
| 673 | }, | 724 | }, |