| ... | ... | @@ -252,9 +252,9 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { |
| 252 | 252 | try self.populateMetadata(); |
| 253 | 253 | try self.parseInputFiles(files); |
| 254 | 254 | try self.resolveImports(); |
| 255 | | try self.allocateTextSegment(); |
| 256 | | try self.allocateDataSegment(); |
| 257 | | try self.allocateLinkeditSegment(); |
| 255 | self.allocateTextSegment(); |
| 256 | self.allocateDataSegment(); |
| 257 | self.allocateLinkeditSegment(); |
| 258 | 258 | try self.writeStubHelperCommon(); |
| 259 | 259 | try self.resolveSymbols(); |
| 260 | 260 | try self.doRelocs(); |
| ... | ... | @@ -317,20 +317,13 @@ fn parseObjectFile(self: *Zld, object: *const Object) !void { |
| 317 | 317 | if (mem.eql(u8, sectname, "__thread_vars")) { |
| 318 | 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 | 320 | try seg.append(self.allocator, .{ |
| 328 | 321 | .sectname = makeStaticString(&sect.sectname), |
| 329 | 322 | .segname = makeStaticString(&sect.segname), |
| 330 | 323 | .addr = 0, |
| 331 | 324 | .size = 0, |
| 332 | 325 | .offset = 0, |
| 333 | | .@"align" = alignment, |
| 326 | .@"align" = sect.@"align", |
| 334 | 327 | .reloff = 0, |
| 335 | 328 | .nreloc = 0, |
| 336 | 329 | .flags = sect.flags, |
| ... | ... | @@ -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 | 433 | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 441 | 434 | const nexterns = @intCast(u32, self.lazy_imports.items().len); |
| 442 | 435 | |
| ... | ... | @@ -457,7 +450,7 @@ fn allocateTextSegment(self: *Zld) !void { |
| 457 | 450 | sizeofcmds += lc.cmdsize(); |
| 458 | 451 | } |
| 459 | 452 | |
| 460 | | try self.allocateSegment( |
| 453 | self.allocateSegment( |
| 461 | 454 | self.text_segment_cmd_index.?, |
| 462 | 455 | 0, |
| 463 | 456 | sizeofcmds, |
| ... | ... | @@ -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 | 462 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 470 | 463 | const nonlazy = @intCast(u32, self.nonlazy_imports.items().len); |
| 471 | 464 | const lazy = @intCast(u32, self.lazy_imports.items().len); |
| ... | ... | @@ -482,16 +475,16 @@ fn allocateDataSegment(self: *Zld) !void { |
| 482 | 475 | |
| 483 | 476 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 484 | 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 | 482 | const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 490 | 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 | 488 | const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize; |
| 496 | 489 | const seg = &self.load_commands.items[index].Segment; |
| 497 | 490 | |
| ... | ... | @@ -565,39 +558,72 @@ fn writeStubHelperCommon(self: *Zld) !void { |
| 565 | 558 | }, |
| 566 | 559 | .aarch64 => { |
| 567 | 560 | var code: [6 * @sizeOf(u32)]u8 = undefined; |
| 568 | | { |
| 561 | data_blk_outer: { |
| 562 | const this_addr = stub_helper.addr; |
| 569 | 563 | const target_addr = data.addr + data.size - @sizeOf(u64); |
| 570 | | const displacement = @bitCast(u21, try math.cast(i21, target_addr - stub_helper.addr)); |
| 571 | | // adr x17, disp |
| 572 | | mem.writeIntLittle(u32, code[0..4], Arm64.adr(17, displacement).toU32()); |
| 573 | | // TODO check if adr is enough and expand into adrp + add if not. |
| 574 | | // nop in case we need to expand adr for adrp followed by add. |
| 575 | | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32()); |
| 564 | data_blk: { |
| 565 | const displacement = math.cast(i21, target_addr - this_addr) catch |_| break :data_blk; |
| 566 | // adr x17, disp |
| 567 | mem.writeIntLittle(u32, code[0..4], Arm64.adr(17, @bitCast(u21, displacement)).toU32()); |
| 568 | // nop |
| 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 | 589 | // stp x16, x17, [sp, #-16]! |
| 578 | 590 | code[8] = 0xf0; |
| 579 | 591 | code[9] = 0x47; |
| 580 | 592 | code[10] = 0xbf; |
| 581 | 593 | code[11] = 0xa9; |
| 582 | | binder: { |
| 594 | binder_blk_outer: { |
| 583 | 595 | const dyld_stub_binder = self.nonlazy_imports.get("dyld_stub_binder").?; |
| 584 | | const addr = (got.addr + dyld_stub_binder.index * @sizeOf(u64)); |
| 585 | | const displacement = math.divExact(u64, addr - stub_helper.addr - 3 * @sizeOf(u32), 4) catch |_| { |
| 586 | | log.warn("0x{x}", .{addr - stub_helper.addr - 3 * @sizeOf(u32)}); |
| 596 | const this_addr = stub_helper.addr + 3 * @sizeOf(u32); |
| 597 | const target_addr = (got.addr + dyld_stub_binder.index * @sizeOf(u64)); |
| 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 | 612 | // Pad with nop to please division. |
| 588 | 613 | // nop |
| 589 | 614 | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.nop().toU32()); |
| 590 | 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 | 616 | mem.writeIntLittle(u32, code[16..20], Arm64.ldr(16, literal, 1).toU32()); |
| 594 | | break :binder; |
| 595 | | }; |
| 596 | | const literal = try math.cast(u19, displacement); // TODO use adrp + add if we exceed the range. |
| 597 | | // ldr x16, label |
| 598 | | mem.writeIntLittle(u32, code[12..16], Arm64.ldr(16, literal, 1).toU32()); |
| 599 | | // nop |
| 600 | | mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.nop().toU32()); |
| 617 | break :binder_blk_outer; |
| 618 | } |
| 619 | // Use adrp followed by ldr(immediate). |
| 620 | const this_page = @intCast(i32, this_addr >> 12); |
| 621 | const target_page = @intCast(i32, target_addr >> 12); |
| 622 | const pages = @bitCast(u21, @intCast(i21, target_page - this_page)); |
| 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 | 628 | // br x16 |
| 603 | 629 | code[20] = 0x00; |
| ... | ... | @@ -662,12 +688,37 @@ fn writeStub(self: *Zld, index: u32) !void { |
| 662 | 688 | }, |
| 663 | 689 | .aarch64 => { |
| 664 | 690 | assert(la_ptr_addr >= stub_addr); |
| 665 | | const displacement = try math.divExact(u64, la_ptr_addr - stub_addr - @sizeOf(u32), 4); |
| 666 | | const literal = try math.cast(u19, displacement); |
| 667 | | // nop |
| 668 | | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32()); |
| 669 | | // ldr x16, literal |
| 670 | | mem.writeIntLittle(u32, code[4..8], Arm64.ldr(16, literal, 1).toU32()); |
| 691 | outer: { |
| 692 | const this_addr = stub_addr; |
| 693 | const target_addr = la_ptr_addr; |
| 694 | inner: { |
| 695 | const displacement = math.divExact(u64, target_addr - this_addr, 4) catch |_| break :inner; |
| 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 | 722 | // br x16 |
| 672 | 723 | mem.writeIntLittle(u32, code[8..12], Arm64.br(16).toU32()); |
| 673 | 724 | }, |