Commit a04bc1ed14

Jakub Konka <kubkon@jakubkonka.com>
2021-07-07 13:47:04
zld: update relocs and start prepping for segment allocs
1 parent dfa69e3
Changed files (3)
src/link/MachO/Object.zig
@@ -48,8 +48,6 @@ dwarf_debug_ranges_index: ?u16 = null,
 
 symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},
 strtab: std.ArrayListUnmanaged(u8) = .{},
-
-initializers: std.ArrayListUnmanaged(u32) = .{},
 data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
 
 symbols: std.ArrayListUnmanaged(*Symbol) = .{},
@@ -157,7 +155,6 @@ pub fn deinit(self: *Object) void {
     }
     self.load_commands.deinit(self.allocator);
     self.data_in_code_entries.deinit(self.allocator);
-    self.initializers.deinit(self.allocator);
     self.symtab.deinit(self.allocator);
     self.strtab.deinit(self.allocator);
     self.symbols.deinit(self.allocator);
@@ -573,6 +570,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
             symbol.payload = .{
                 .regular = .{
                     .linkage = .translation_unit,
+                    .address = sect.addr,
                     .segment_id = match.seg,
                     .section_id = match.sect,
                     .file = self,
@@ -657,6 +655,13 @@ pub fn symbolFromReloc(self: *Object, rel: macho.relocation_info) !*Symbol {
                 });
                 defer self.allocator.free(name);
                 const symbol = try Symbol.new(self.allocator, name);
+                symbol.payload = .{
+                    .regular = .{
+                        .linkage = .translation_unit,
+                        .address = sect.addr,
+                        .file = self,
+                    },
+                };
                 try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol);
                 break :symbol symbol;
             };
@@ -666,22 +671,6 @@ pub fn symbolFromReloc(self: *Object, rel: macho.relocation_info) !*Symbol {
     return symbol;
 }
 
-pub fn parseInitializers(self: *Object) !void {
-    const index = self.mod_init_func_section_index orelse return;
-    const section = self.sections.items[index];
-
-    log.debug("parsing initializers in {s}", .{self.name.?});
-
-    // Parse C++ initializers
-    const relocs = section.relocs orelse unreachable;
-    try self.initializers.ensureCapacity(self.allocator, relocs.len);
-    for (relocs) |rel| {
-        self.initializers.appendAssumeCapacity(rel.target.symbol);
-    }
-
-    mem.reverse(u32, self.initializers.items);
-}
-
 fn parseSymtab(self: *Object) !void {
     const index = self.symtab_cmd_index orelse return;
     const symtab_cmd = self.load_commands.items[index].Symtab;
src/link/MachO/reloc.zig
@@ -48,33 +48,24 @@ pub const Relocation = struct {
         /// => * is unreachable
         is_64bit: bool,
 
+        source_sect_addr: ?u64 = null,
+
         pub fn resolve(self: Unsigned, base: Relocation, source_addr: u64, target_addr: u64) !void {
-            //     const addend = if (unsigned.base.target == .section)
-            //         unsigned.addend - @intCast(i64, args.source_target_sect_addr.?)
-            //     else
-            //         unsigned.addend;
-
-            //     const result = if (args.subtractor) |subtractor|
-            //         @intCast(i64, args.target_addr) - @intCast(i64, subtractor) + addend
-            //     else
-            //         @intCast(i64, args.target_addr) + addend;
-
-            //     log.debug("    | calculated addend 0x{x}", .{addend});
-            //     log.debug("    | calculated unsigned value 0x{x}", .{result});
-
-            //     if (unsigned.is_64bit) {
-            //         mem.writeIntLittle(
-            //             u64,
-            //             unsigned.base.code[0..8],
-            //             @bitCast(u64, result),
-            //         );
-            //     } else {
-            //         mem.writeIntLittle(
-            //             u32,
-            //             unsigned.base.code[0..4],
-            //             @truncate(u32, @bitCast(u64, result)),
-            //         );
-            //     }
+            const addend = if (self.source_sect_addr) |addr|
+                self.addend - addr
+            else
+                self.addend;
+
+            const result = if (self.subtractor) |subtractor|
+                @intCast(i64, target_addr) - @intCast(i64, subtractor.payload.regular.address) + addend
+            else
+                @intCast(i64, target_addr) + addend;
+
+            if (self.is_64bit) {
+                mem.writeIntLittle(u64, base.block.code[base.offset..][0..8], @bitCast(u64, result));
+            } else {
+                mem.writeIntLittle(u32, base.block.code[base.offset..][0..4], @truncate(u32, @bitCast(u64, result)));
+            }
         }
 
         pub fn format(self: Unsigned, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
@@ -191,56 +182,119 @@ pub const Relocation = struct {
         pub fn resolve(self: PageOff, base: Relocation, source_addr: u64, target_addr: u64) !void {
             switch (self.kind) {
                 .page => {
-                    //     const target_addr = if (page_off.addend) |addend| args.target_addr + addend else args.target_addr;
-                    //     const narrowed = @truncate(u12, target_addr);
-
-                    //     log.debug("    | narrowed address within the page 0x{x}", .{narrowed});
-                    //     log.debug("    | {s} opcode", .{page_off.op_kind});
-
-                    //     var inst = page_off.inst;
-                    //     if (page_off.op_kind == .arithmetic) {
-                    //         inst.add_subtract_immediate.imm12 = narrowed;
-                    //     } else {
-                    //         const offset: u12 = blk: {
-                    //             if (inst.load_store_register.size == 0) {
-                    //                 if (inst.load_store_register.v == 1) {
-                    //                     // 128-bit SIMD is scaled by 16.
-                    //                     break :blk try math.divExact(u12, narrowed, 16);
-                    //                 }
-                    //                 // Otherwise, 8-bit SIMD or ldrb.
-                    //                 break :blk narrowed;
-                    //             } else {
-                    //                 const denom: u4 = try math.powi(u4, 2, inst.load_store_register.size);
-                    //                 break :blk try math.divExact(u12, narrowed, denom);
-                    //             }
-                    //         };
-                    //         inst.load_store_register.offset = offset;
-                    //     }
-
-                    //     mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32());
+                    const actual_target_addr = if (self.addend) |addend| target_addr + addend else target_addr;
+                    const narrowed = @truncate(u12, actual_target_addr);
+
+                    const op_kind = self.op_kind orelse unreachable;
+                    var inst: aarch64.Instruction = blk: {
+                        switch (op_kind) {
+                            .arithmetic => {
+                                break :blk .{
+                                    .add_subtract_immediate = mem.bytesToValue(
+                                        meta.TagPayload(
+                                            aarch64.Instruction,
+                                            aarch64.Instruction.add_subtract_immediate,
+                                        ),
+                                        base.block.code[base.offset..][0..4],
+                                    ),
+                                };
+                            },
+                            .load => {
+                                break :blk .{
+                                    .load_store_register = mem.bytesToValue(
+                                        meta.TagPayload(
+                                            aarch64.Instruction,
+                                            aarch64.Instruction.load_store_register,
+                                        ),
+                                        base.block.code[base.offset..][0..4],
+                                    ),
+                                };
+                            },
+                        }
+                    };
+
+                    if (op_kind == .arithmetic) {
+                        inst.add_subtract_immediate.imm12 = narrowed;
+                    } else {
+                        const offset: u12 = blk: {
+                            if (inst.load_store_register.size == 0) {
+                                if (inst.load_store_register.v == 1) {
+                                    // 128-bit SIMD is scaled by 16.
+                                    break :blk try math.divExact(u12, narrowed, 16);
+                                }
+                                // Otherwise, 8-bit SIMD or ldrb.
+                                break :blk narrowed;
+                            } else {
+                                const denom: u4 = try math.powi(u4, 2, inst.load_store_register.size);
+                                break :blk try math.divExact(u12, narrowed, denom);
+                            }
+                        };
+                        inst.load_store_register.offset = offset;
+                    }
 
+                    mem.writeIntLittle(u32, base.block.code[base.offset..][0..4], inst.toU32());
                 },
                 .got => {
-                    //     const narrowed = @truncate(u12, args.target_addr);
-
-                    //     log.debug("    | narrowed address within the page 0x{x}", .{narrowed});
-
-                    //     var inst = page_off.inst;
-                    //     const offset = try math.divExact(u12, narrowed, 8);
-                    //     inst.load_store_register.offset = offset;
-
-                    //     mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32());
+                    const narrowed = @truncate(u12, target_addr);
+                    var inst = mem.bytesToValue(
+                        meta.TagPayload(
+                            aarch64.Instruction,
+                            aarch64.Instruction.load_store_register,
+                        ),
+                        base.block.code[base.offset..][0..4],
+                    );
+                    const offset = try math.divExact(u12, narrowed, 8);
+                    inst.load_store_register.offset = offset;
+                    mem.writeIntLittle(u32, base.block.code[base.offset..][0..4], inst.toU32());
                 },
                 .tlvp => {
-
-                    //     const narrowed = @truncate(u12, args.target_addr);
-
-                    //     log.debug("    | narrowed address within the page 0x{x}", .{narrowed});
-
-                    //     var inst = page_off.inst;
-                    //     inst.add_subtract_immediate.imm12 = narrowed;
-
-                    //     mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32());
+                    const RegInfo = struct {
+                        rd: u5,
+                        rn: u5,
+                        size: u1,
+                    };
+                    const reg_info: RegInfo = blk: {
+                        if (isArithmeticOp(base.block.code[base.offset..][0..4])) {
+                            const inst = mem.bytesToValue(
+                                meta.TagPayload(
+                                    aarch64.Instruction,
+                                    aarch64.Instruction.add_subtract_immediate,
+                                ),
+                                base.block.code[base.offset..][0..4],
+                            );
+                            break :blk .{
+                                .rd = inst.rd,
+                                .rn = inst.rn,
+                                .size = inst.sf,
+                            };
+                        } else {
+                            const inst = mem.bytesToValue(
+                                meta.TagPayload(
+                                    aarch64.Instruction,
+                                    aarch64.Instruction.load_store_register,
+                                ),
+                                base.block.code[base.offset..][0..4],
+                            );
+                            break :blk .{
+                                .rd = inst.rt,
+                                .rn = inst.rn,
+                                .size = @truncate(u1, inst.size),
+                            };
+                        }
+                    };
+                    const narrowed = @truncate(u12, target_addr);
+                    var inst = aarch64.Instruction{
+                        .add_subtract_immediate = .{
+                            .rd = reg_info.rd,
+                            .rn = reg_info.rn,
+                            .imm12 = narrowed,
+                            .sh = 0,
+                            .s = 0,
+                            .op = 0,
+                            .sf = reg_info.size,
+                        },
+                    };
+                    mem.writeIntLittle(u32, base.block.code[base.offset..][0..4], inst.toU32());
                 },
             }
         }
@@ -661,12 +715,17 @@ pub const Parser = struct {
             mem.readIntLittle(i64, self.block.code[parsed.offset..][0..8])
         else
             mem.readIntLittle(i32, self.block.code[parsed.offset..][0..4]);
+        const source_sect_addr = if (rel.r_extern == 0) blk: {
+            if (parsed.target.payload == .regular) break :blk parsed.target.payload.regular.address;
+            break :blk null;
+        } else null;
 
         parsed.payload = .{
             .unsigned = .{
                 .subtractor = self.subtractor,
                 .is_64bit = is_64bit,
                 .addend = addend,
+                .source_sect_addr = source_sect_addr,
             },
         };
 
src/link/MachO/Zld.zig
@@ -120,16 +120,6 @@ pub const Output = struct {
     install_name: ?[]const u8 = null,
 };
 
-const TlvOffset = struct {
-    source_addr: u64,
-    offset: u64,
-
-    fn cmp(context: void, a: TlvOffset, b: TlvOffset) bool {
-        _ = context;
-        return a.source_addr < b.source_addr;
-    }
-};
-
 pub const TextBlock = struct {
     local_sym_index: u32,
     aliases: ?[]u32 = null,
@@ -274,12 +264,11 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
     try self.parseLibs(args.libs, args.syslibroot);
     try self.resolveSymbols();
     try self.parseTextBlocks();
+    try self.sortSections();
+    try self.addRpaths(args.rpaths);
+    try self.addDataInCodeLC();
+    try self.addCodeSignatureLC();
     return error.TODO;
-    // try self.updateMetadata();
-    // try self.sortSections();
-    // try self.addRpaths(args.rpaths);
-    // try self.addDataInCodeLC();
-    // try self.addCodeSignatureLC();
     // try self.allocateTextSegment();
     // try self.allocateDataConstSegment();
     // try self.allocateDataSegment();
@@ -343,106 +332,6 @@ fn parseLibs(self: *Zld, libs: []const []const u8, syslibroot: ?[]const u8) !voi
     }
 }
 
-fn mapAndUpdateSections(
-    self: *Zld,
-    object: *Object,
-    source_sect_id: u16,
-    target_seg_id: u16,
-    target_sect_id: u16,
-) !void {
-    const source_sect = &object.sections.items[source_sect_id];
-    const target_seg = &self.load_commands.items[target_seg_id].Segment;
-    const target_sect = &target_seg.sections.items[target_sect_id];
-
-    const alignment = try math.powi(u32, 2, target_sect.@"align");
-    const offset = mem.alignForwardGeneric(u64, target_sect.size, alignment);
-    const size = mem.alignForwardGeneric(u64, source_sect.inner.size, alignment);
-
-    log.debug("{s}: '{s},{s}' mapped to '{s},{s}' from 0x{x} to 0x{x}", .{
-        object.name.?,
-        segmentName(source_sect.inner),
-        sectionName(source_sect.inner),
-        segmentName(target_sect.*),
-        sectionName(target_sect.*),
-        offset,
-        offset + size,
-    });
-    log.debug("  | flags 0x{x}", .{source_sect.inner.flags});
-
-    source_sect.target_map = .{
-        .segment_id = target_seg_id,
-        .section_id = target_sect_id,
-        .offset = @intCast(u32, offset),
-    };
-    target_sect.size = offset + size;
-}
-
-fn updateMetadata(self: *Zld) !void {
-    for (self.objects.items) |object| {
-        // Find ideal section alignment and update section mappings
-        for (object.sections.items) |sect, sect_id| {
-            const match = (try self.getMatchingSection(sect.inner)) orelse {
-                log.debug("{s}: unhandled section type 0x{x} for '{s},{s}'", .{
-                    object.name.?,
-                    sect.inner.flags,
-                    segmentName(sect.inner),
-                    sectionName(sect.inner),
-                });
-                continue;
-            };
-            const target_seg = &self.load_commands.items[match.seg].Segment;
-            const target_sect = &target_seg.sections.items[match.sect];
-            target_sect.@"align" = math.max(target_sect.@"align", sect.inner.@"align");
-
-            try self.mapAndUpdateSections(object, @intCast(u16, sect_id), match.seg, match.sect);
-        }
-    }
-
-    tlv_align: {
-        const has_tlv =
-            self.tlv_section_index != null or
-            self.tlv_data_section_index != null or
-            self.tlv_bss_section_index != null;
-
-        if (!has_tlv) break :tlv_align;
-
-        const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
-
-        if (self.tlv_section_index) |index| {
-            const sect = &seg.sections.items[index];
-            sect.@"align" = 3; // __thread_vars is always 8byte aligned
-        }
-
-        // Apparently __tlv_data and __tlv_bss need to have matching alignment, so fix it up.
-        // <rdar://problem/24221680> All __thread_data and __thread_bss sections must have same alignment
-        // https://github.com/apple-opensource/ld64/blob/e28c028b20af187a16a7161d89e91868a450cadc/src/ld/ld.cpp#L1172
-        const data_align: u32 = data: {
-            if (self.tlv_data_section_index) |index| {
-                const sect = &seg.sections.items[index];
-                break :data sect.@"align";
-            }
-            break :tlv_align;
-        };
-        const bss_align: u32 = bss: {
-            if (self.tlv_bss_section_index) |index| {
-                const sect = &seg.sections.items[index];
-                break :bss sect.@"align";
-            }
-            break :tlv_align;
-        };
-        const max_align = math.max(data_align, bss_align);
-
-        if (self.tlv_data_section_index) |index| {
-            const sect = &seg.sections.items[index];
-            sect.@"align" = max_align;
-        }
-        if (self.tlv_bss_section_index) |index| {
-            const sect = &seg.sections.items[index];
-            sect.@"align" = max_align;
-        }
-    }
-}
-
 pub const MatchingSection = struct {
     seg: u16,
     sect: u16,
@@ -946,36 +835,6 @@ fn sortSections(self: *Zld) !void {
             maybe_index.* = new_index;
         }
     }
-
-    for (self.objects.items) |object| {
-        for (object.sections.items) |*sect| {
-            const target_map = sect.target_map orelse continue;
-
-            const new_index = blk: {
-                if (self.text_segment_cmd_index.? == target_map.segment_id) {
-                    break :blk text_index_mapping.get(target_map.section_id) orelse unreachable;
-                } else if (self.data_const_segment_cmd_index.? == target_map.segment_id) {
-                    break :blk data_const_index_mapping.get(target_map.section_id) orelse unreachable;
-                } else if (self.data_segment_cmd_index.? == target_map.segment_id) {
-                    break :blk data_index_mapping.get(target_map.section_id) orelse unreachable;
-                } else unreachable;
-            };
-
-            log.debug("remapping in {s}: '{s},{s}': {} => {}", .{
-                object.name.?,
-                segmentName(sect.inner),
-                sectionName(sect.inner),
-                target_map.section_id,
-                new_index,
-            });
-
-            sect.target_map = .{
-                .segment_id = target_map.segment_id,
-                .section_id = new_index,
-                .offset = target_map.offset,
-            };
-        }
-    }
 }
 
 fn allocateTextSegment(self: *Zld) !void {
@@ -1431,6 +1290,7 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {
             symbol.payload = .{
                 .regular = .{
                     .linkage = .translation_unit,
+                    .address = sym.n_value,
                     .weak_ref = Symbol.isWeakRef(sym),
                     .file = object,
                     .local_sym_index = @intCast(u32, self.locals.items.len),
@@ -1470,6 +1330,7 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {
                 symbol.payload = .{
                     .regular = .{
                         .linkage = linkage,
+                        .address = sym.n_value,
                         .weak_ref = Symbol.isWeakRef(sym),
                         .file = object,
                     },
@@ -1672,80 +1533,6 @@ fn parseTextBlocks(self: *Zld) !void {
     }
 }
 
-fn resolveRelocsAndWriteSections(self: *Zld) !void {
-    for (self.objects.items) |object| {
-        log.debug("relocating object {s}", .{object.name});
-
-        for (object.sections.items) |sect| {
-            if (sectionType(sect.inner) == macho.S_MOD_INIT_FUNC_POINTERS or
-                sectionType(sect.inner) == macho.S_MOD_TERM_FUNC_POINTERS) continue;
-
-            const segname = segmentName(sect.inner);
-            const sectname = sectionName(sect.inner);
-
-            log.debug("relocating section '{s},{s}'", .{ segname, sectname });
-
-            // Get target mapping
-            const target_map = sect.target_map orelse {
-                log.debug("no mapping for '{s},{s}'; skipping", .{ segname, sectname });
-                continue;
-            };
-            const target_seg = self.load_commands.items[target_map.segment_id].Segment;
-            const target_sect = target_seg.sections.items[target_map.section_id];
-            const target_sect_addr = target_sect.addr + target_map.offset;
-            const target_sect_off = target_sect.offset + target_map.offset;
-
-            if (sect.relocs) |relocs| {
-                for (relocs) |rel| {
-                    const source_addr = target_sect_addr + rel.offset;
-
-                    var args: reloc.Relocation.ResolveArgs = .{
-                        .source_addr = source_addr,
-                        .target_addr = undefined,
-                    };
-
-                    switch (rel.@"type") {
-                        .unsigned => {
-                            args.target_addr = try self.relocTargetAddr(object, rel.target);
-
-                            const unsigned = rel.cast(reloc.Unsigned) orelse unreachable;
-                            if (unsigned.subtractor) |subtractor| {
-                                args.subtractor = try self.relocTargetAddr(object, subtractor);
-                            }
-                            if (rel.target == .section) {
-                                const source_sect = object.sections.items[rel.target.section];
-                                args.source_source_sect_addr = sect.inner.addr;
-                                args.source_target_sect_addr = source_sect.inner.addr;
-                            }
-                        },
-                        .got_page, .got_page_off, .got_load, .got, .pointer_to_got => {
-                            const dc_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
-                            const got = dc_seg.sections.items[self.got_section_index.?];
-                            const sym = object.symbols.items[rel.target.symbol];
-                            const got_index = sym.got_index orelse {
-                                log.err("expected GOT index relocating symbol '{s}'", .{sym.name});
-                                log.err("this is an internal linker error", .{});
-                                return error.FailedToResolveRelocationTarget;
-                            };
-                            args.target_addr = got.addr + got_index * @sizeOf(u64);
-                        },
-                        else => |tt| {
-                            if (tt == .signed and rel.target == .section) {
-                                const source_sect = object.sections.items[rel.target.section];
-                                args.source_source_sect_addr = sect.inner.addr;
-                                args.source_target_sect_addr = source_sect.inner.addr;
-                            }
-                            args.target_addr = try self.relocTargetAddr(object, rel.target);
-                        },
-                    }
-
-                    try rel.resolve(args);
-                }
-            }
-        }
-    }
-}
-
 fn populateMetadata(self: *Zld) !void {
     if (self.pagezero_segment_cmd_index == null) {
         self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);