authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-02-25 22:04:28+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-03-17 19:59:13+01:00
log586c704212b5453281cc27626f1ae46982a62d16
tree665ae83451630d493e8595263da349643b7c6681
parente825a15b0588d2ae4d3c6ab28fb8d8fd2ae05288

zld: pass stage2 tests linked with zld!


2 files changed, 120 insertions(+), 79 deletions(-)

src/link/MachO/Zld.zig+97-75
......@@ -252,9 +252,9 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {
252252 try self.populateMetadata();
253253 try self.parseInputFiles(files);
254254 try self.resolveImports();
255 self.allocateTextSegment();
256 self.allocateDataSegment();
257 self.allocateLinkeditSegment();
255 try self.allocateTextSegment();
256 try self.allocateDataSegment();
257 try self.allocateLinkeditSegment();
258258 try self.writeStubHelperCommon();
259259 try self.resolveSymbols();
260260 try self.doRelocs();
......@@ -317,13 +317,20 @@ fn parseObjectFile(self: *Zld, object: *const Object) !void {
317317 if (mem.eql(u8, sectname, "__thread_vars")) {
318318 self.tlv_section_index = sect_index;
319319 }
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 };
320327 try seg.append(self.allocator, .{
321328 .sectname = makeStaticString(&sect.sectname),
322329 .segname = makeStaticString(&sect.segname),
323330 .addr = 0,
324331 .size = 0,
325332 .offset = 0,
326 .@"align" = sect.@"align",
333 .@"align" = alignment,
327334 .reloff = 0,
328335 .nreloc = 0,
329336 .flags = sect.flags,
......@@ -429,7 +436,7 @@ fn resolveImports(self: *Zld) !void {
429436 });
430437}
431438
432fn allocateTextSegment(self: *Zld) void {
439fn allocateTextSegment(self: *Zld) !void {
433440 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
434441 const nexterns = @intCast(u32, self.lazy_imports.items().len);
435442
......@@ -450,10 +457,16 @@ fn allocateTextSegment(self: *Zld) void {
450457 sizeofcmds += lc.cmdsize();
451458 }
452459
453 self.allocateSegment(self.text_segment_cmd_index.?, 0, sizeofcmds, true);
460 try self.allocateSegment(
461 self.text_segment_cmd_index.?,
462 0,
463 // sizeofcmds + 10 * 4 * @sizeOf(u32),
464 3140,
465 true,
466 );
454467}
455468
456fn allocateDataSegment(self: *Zld) void {
469fn allocateDataSegment(self: *Zld) !void {
457470 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
458471 const nonlazy = @intCast(u32, self.nonlazy_imports.items().len);
459472 const lazy = @intCast(u32, self.lazy_imports.items().len);
......@@ -470,16 +483,16 @@ fn allocateDataSegment(self: *Zld) void {
470483
471484 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
472485 const offset = text_seg.inner.fileoff + text_seg.inner.filesize;
473 self.allocateSegment(self.data_segment_cmd_index.?, offset, 0, false);
486 try self.allocateSegment(self.data_segment_cmd_index.?, offset, 0, false);
474487}
475488
476fn allocateLinkeditSegment(self: *Zld) void {
489fn allocateLinkeditSegment(self: *Zld) !void {
477490 const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
478491 const offset = data_seg.inner.fileoff + data_seg.inner.filesize;
479 self.allocateSegment(self.linkedit_segment_cmd_index.?, offset, 0, false);
492 try self.allocateSegment(self.linkedit_segment_cmd_index.?, offset, 0, false);
480493}
481494
482fn allocateSegment(self: *Zld, index: u16, offset: u64, start: u64, reverse: bool) void {
495fn allocateSegment(self: *Zld, index: u16, offset: u64, start: u64, reverse: bool) !void {
483496 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;
484497 const seg = &self.load_commands.items[index].Segment;
485498
......@@ -495,23 +508,27 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64, start: u64, reverse: boo
495508 seg.inner.filesize = aligned_size;
496509
497510 // Allocate section offsets
498 if (reverse) {
499 var end_off: u64 = seg.inner.fileoff + seg.inner.filesize;
500 var count: usize = seg.sections.items.len;
501 while (count > 0) : (count -= 1) {
502 const sec = &seg.sections.items[count - 1];
503 end_off -= mem.alignForwardGeneric(u64, sec.size, @sizeOf(u32)); // TODO Should we always align to 4?
504 sec.offset = @intCast(u32, end_off);
505 sec.addr = base_vmaddr + end_off;
506 }
507 } else {
508 var next_off: u64 = seg.inner.fileoff;
509 for (seg.sections.items) |*sect| {
510 sect.offset = @intCast(u32, next_off);
511 sect.addr = base_vmaddr + next_off;
512 next_off += mem.alignForwardGeneric(u64, sect.size, @sizeOf(u32)); // TODO Should we always align to 4?
513 }
514 }
511 // if (reverse) {
512 // var end_off: u64 = seg.inner.fileoff + seg.inner.filesize;
513 // var count: usize = seg.sections.items.len;
514 // while (count > 0) : (count -= 1) {
515 // const sec = &seg.sections.items[count - 1];
516 // const alignment = math.max(@alignOf(u32), try std.math.powi(u32, 2, sec.@"align"));
517 // log.warn("{s} 0x{x} alignment = 0x{x}", .{ parseName(&sec.sectname), sec.@"align", alignment });
518 // end_off -= mem.alignForwardGeneric(u64, sec.size, alignment);
519 // sec.offset = @intCast(u32, end_off);
520 // sec.addr = base_vmaddr + end_off;
521 // }
522 // } else {
523 var next_off: u64 = seg.inner.fileoff + start;
524 for (seg.sections.items) |*sect| {
525 const alignment = math.max(@alignOf(u32), try std.math.powi(u32, 2, sect.@"align"));
526 log.warn("{s} 0x{x} alignment = 0x{x}", .{ parseName(&sect.sectname), sect.@"align", alignment });
527 sect.offset = @intCast(u32, next_off);
528 sect.addr = base_vmaddr + next_off;
529 next_off += mem.alignForwardGeneric(u64, sect.size, alignment);
530 }
531 // }
515532}
516533
517534fn writeStubHelperCommon(self: *Zld) !void {
......@@ -552,33 +569,48 @@ fn writeStubHelperCommon(self: *Zld) !void {
552569 break :blk stub_helper.offset + code_size;
553570 },
554571 .aarch64 => {
555 var code: [4 * @sizeOf(u32)]u8 = undefined;
572 var code: [6 * @sizeOf(u32)]u8 = undefined;
556573 {
557574 const target_addr = data.addr + data.size - @sizeOf(u64);
558575 const displacement = @bitCast(u21, try math.cast(i21, target_addr - stub_helper.addr));
559576 // adr x17, disp
560577 mem.writeIntLittle(u32, code[0..4], Arm64.adr(17, displacement).toU32());
578 // TODO check if adr is enough and expand into adrp + add if not.
579 // nop in case we need to expand adr for adrp followed by add.
580 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32());
561581 }
562582 // stp x16, x17, [sp, #-16]!
563 code[4] = 0xf0;
564 code[5] = 0x47;
565 code[6] = 0xbf;
566 code[7] = 0xa9;
567 {
583 code[8] = 0xf0;
584 code[9] = 0x47;
585 code[10] = 0xbf;
586 code[11] = 0xa9;
587 binder: {
568588 const dyld_stub_binder = self.nonlazy_imports.get("dyld_stub_binder").?;
569589 const addr = (got.addr + dyld_stub_binder.index * @sizeOf(u64));
570 const displacement = try math.divExact(u64, addr - stub_helper.addr - 2 * @sizeOf(u32), 4);
571 const literal = try math.cast(u19, displacement);
590 const displacement = math.divExact(u64, addr - stub_helper.addr - 3 * @sizeOf(u32), 4) catch |_| {
591 log.warn("0x{x}", .{addr - stub_helper.addr - 3 * @sizeOf(u32)});
592 // Pad with nop to please division.
593 // nop
594 mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.nop().toU32());
595 // ldr x16, label
596 const disp = try math.divExact(u64, addr - stub_helper.addr - 4 * @sizeOf(u32), 4);
597 const literal = try math.cast(u19, disp); // TODO use adrp + add if we exceed the range.
598 mem.writeIntLittle(u32, code[16..20], Arm64.ldr(16, literal, 1).toU32());
599 break :binder;
600 };
601 const literal = try math.cast(u19, displacement); // TODO use adrp + add if we exceed the range.
572602 // ldr x16, label
573 mem.writeIntLittle(u32, code[8..12], Arm64.ldr(16, literal, 1).toU32());
603 mem.writeIntLittle(u32, code[12..16], Arm64.ldr(16, literal, 1).toU32());
604 // nop
605 mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.nop().toU32());
574606 }
575607 // br x16
576 code[12] = 0x00;
577 code[13] = 0x02;
578 code[14] = 0x1f;
579 code[15] = 0xd6;
608 code[20] = 0x00;
609 code[21] = 0x02;
610 code[22] = 0x1f;
611 code[23] = 0xd6;
580612 try self.file.?.pwriteAll(&code, stub_helper.offset);
581 break :blk stub_helper.offset + 4 * @sizeOf(u32);
613 break :blk stub_helper.offset + 6 * @sizeOf(u32);
582614 },
583615 else => unreachable,
584616 }
......@@ -635,12 +667,14 @@ fn writeStub(self: *Zld, index: u32) !void {
635667 },
636668 .aarch64 => {
637669 assert(la_ptr_addr >= stub_addr);
638 const displacement = try math.divExact(u64, la_ptr_addr - stub_addr, 4);
670 const displacement = try math.divExact(u64, la_ptr_addr - stub_addr - @sizeOf(u32), 4);
639671 const literal = try math.cast(u19, displacement);
672 // nop
673 mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32());
640674 // ldr x16, literal
641 mem.writeIntLittle(u32, code[0..4], Arm64.ldr(16, literal, 1).toU32());
675 mem.writeIntLittle(u32, code[4..8], Arm64.ldr(16, literal, 1).toU32());
642676 // br x16
643 mem.writeIntLittle(u32, code[4..8], Arm64.br(16).toU32());
677 mem.writeIntLittle(u32, code[8..12], Arm64.br(16).toU32());
644678 },
645679 else => unreachable,
646680 }
......@@ -722,7 +756,8 @@ fn resolveSymbols(self: *Zld) !void {
722756 const sym_name = object.getString(sym.n_strx);
723757
724758 if (isLocal(&sym) and self.locals.get(sym_name) != null) {
725 log.warn("symbol '{s}' already exists; skipping", .{sym_name});
759 log.warn("local symbol '{s}' defined multiple times; removing", .{sym_name});
760 self.locals.swapRemoveAssertDiscard(sym_name);
726761 continue;
727762 }
728763
......@@ -978,12 +1013,6 @@ fn doRelocs(self: *Zld) !void {
9781013 const this_page = @intCast(i32, this_addr >> 12);
9791014 const target_page = @intCast(i32, ta >> 12);
9801015 const pages = @bitCast(u21, @intCast(i21, target_page - this_page));
981 if (pages == 0) {
982 // No need to execute adrp. Instead, replace with a nop.
983 log.warn(" | replacing ADRP with NOP", .{});
984 mem.writeIntLittle(u32, inst, aarch64.Instruction.nop().toU32());
985 continue;
986 }
9871016 log.warn(" | moving by {} pages", .{pages});
9881017 var parsed = mem.bytesAsValue(meta.TagPayload(Arm64, Arm64.Address), inst);
9891018 parsed.immhi = @truncate(u19, pages >> 2);
......@@ -1000,12 +1029,6 @@ fn doRelocs(self: *Zld) !void {
10001029 var parsed = mem.bytesAsValue(meta.TagPayload(Arm64, Arm64.Add), inst);
10011030 const ta = if (addend) |a| target_addr + a else target_addr;
10021031 const narrowed = @truncate(u12, ta);
1003 if (narrowed == 0) {
1004 // No need to execute add. Instead, replace with a nop.
1005 log.warn(" | replacing ADD with NOP", .{});
1006 mem.writeIntLittle(u32, inst, aarch64.Instruction.nop().toU32());
1007 continue;
1008 }
10091032 parsed.offset = narrowed;
10101033 } else {
10111034 log.warn(" | detected LDR/STR opcode", .{});
......@@ -1013,20 +1036,18 @@ fn doRelocs(self: *Zld) !void {
10131036 var parsed = mem.bytesAsValue(meta.TagPayload(Arm64, Arm64.LoadRegister), inst);
10141037 const ta = if (addend) |a| target_addr + a else target_addr;
10151038 const narrowed = @truncate(u12, ta);
1016 if (narrowed == 0) {
1017 // No need to execute ldr/str. Instead, replace with a nop.
1018 log.warn(" | replacing LDR/STR with NOP", .{});
1019 mem.writeIntLittle(u32, inst, aarch64.Instruction.nop().toU32());
1020 continue;
1021 }
1022 const denom: u12 = if (parsed.size == 1) 8 else 4;
1023 const offset = math.divExact(u12, narrowed, denom) catch |_| {
1024 // If we are here, then this means we are not able to divide the offset
1025 // exactly by the required denominator. Therefore, we will use add instead of
1026 // ldr as we expect ldr to follow this instruction nonetheless.
1027 // TODO I believe ldr/str can only occur for GOT_LOAD_PAGEOFF12.
1028 mem.writeIntLittle(u32, inst, Arm64.add(parsed.rn, parsed.rn, narrowed, parsed.size).toU32());
1029 continue;
1039 const offset: u12 = blk: {
1040 if (parsed.size == 0) {
1041 break :blk narrowed;
1042 } else {
1043 const denom: u4 = try math.powi(u4, 2, parsed.size);
1044 const offf = math.divExact(u12, narrowed, denom) catch |_| {
1045 log.warn(" | narrowed 0x{x}", .{narrowed});
1046 log.warn(" | denom 0x{x}", .{denom});
1047 continue;
1048 };
1049 break :blk offf;
1050 }
10301051 };
10311052 parsed.offset = offset;
10321053 }
......@@ -1046,7 +1067,7 @@ fn doRelocs(self: *Zld) !void {
10461067 break :blk .{ .rt = curr.rt, .rn = curr.rn, .size = curr.size };
10471068 } else {
10481069 const curr = mem.bytesAsValue(meta.TagPayload(Arm64, Arm64.LoadRegister), inst);
1049 break :blk .{ .rt = curr.rt, .rn = curr.rn, .size = curr.size };
1070 break :blk .{ .rt = curr.rt, .rn = curr.rn, .size = @truncate(u1, curr.size) };
10501071 }
10511072 };
10521073 const ta = if (addend) |a| target_addr + a else target_addr;
......@@ -1145,6 +1166,7 @@ fn relocTargetAddr(self: *Zld, object: Object, rel: macho.relocation_info, next_
11451166 .segname = source_sect.segname,
11461167 .sectname = source_sect.sectname,
11471168 }).?;
1169 log.warn(" | symbol local to object", .{});
11481170 break :blk target_space.address + sym.n_value - source_sect.addr;
11491171 } else if (isImport(&sym)) {
11501172 // Relocate to either the artifact's local symbol, or an import from
......@@ -1267,7 +1289,7 @@ fn populateMetadata(self: *Zld) !void {
12671289 };
12681290 const stub_size: u4 = switch (self.arch.?) {
12691291 .x86_64 => 6,
1270 .aarch64 => 2 * @sizeOf(u32),
1292 .aarch64 => 3 * @sizeOf(u32),
12711293 else => unreachable, // unhandled architecture type
12721294 };
12731295 try text_seg.append(self.allocator, .{
......@@ -1298,7 +1320,7 @@ fn populateMetadata(self: *Zld) !void {
12981320 .aarch64 => 2,
12991321 else => unreachable, // unhandled architecture type
13001322 };
1301 const stub_helper_size: u5 = switch (self.arch.?) {
1323 const stub_helper_size: u6 = switch (self.arch.?) {
13021324 .x86_64 => 15,
13031325 .aarch64 => 6 * @sizeOf(u32),
13041326 else => unreachable,
src/link/MachO/reloc.zig+23-4
......@@ -26,8 +26,7 @@ pub const Arm64 = union(enum) {
2626 rn: u5,
2727 offset: u12,
2828 _1: u8 = 0b111_0_01_01,
29 size: u1,
30 _2: u1 = 0b1,
29 size: u2,
3130 },
3231 LoadLiteral: packed struct {
3332 reg: u5,
......@@ -135,13 +134,33 @@ pub const Arm64 = union(enum) {
135134 };
136135 }
137136
138 pub fn ldrr(rt: u5, rn: u5, offset: u12, size: u1) Arm64 {
137 pub fn ldrq(rt: u5, rn: u5, offset: u12) Arm64 {
139138 return Arm64{
140139 .LoadRegister = .{
141140 .rt = rt,
142141 .rn = rn,
143142 .offset = offset,
144 .size = size,
143 .size = 0b11,
144 },
145 };
146 }
147 pub fn ldrh(rt: u5, rn: u5, offset: u12) Arm64 {
148 return Arm64{
149 .LoadRegister = .{
150 .rt = rt,
151 .rn = rn,
152 .offset = offset,
153 .size = 0b01,
154 },
155 };
156 }
157 pub fn ldrb(rt: u5, rn: u5, offset: u12) Arm64 {
158 return Arm64{
159 .LoadRegister = .{
160 .rt = rt,
161 .rn = rn,
162 .offset = offset,
163 .size = 0b00,
145164 },
146165 };
147166 }