| ... | @@ -38,6 +38,7 @@ const Module = @import("../Module.zig"); | ... | @@ -38,6 +38,7 @@ const Module = @import("../Module.zig"); |
| 38 | const StringIndexAdapter = std.hash_map.StringIndexAdapter; | 38 | const StringIndexAdapter = std.hash_map.StringIndexAdapter; |
| 39 | const StringIndexContext = std.hash_map.StringIndexContext; | 39 | const StringIndexContext = std.hash_map.StringIndexContext; |
| 40 | const Trie = @import("MachO/Trie.zig"); | 40 | const Trie = @import("MachO/Trie.zig"); |
| | 41 | const Type = @import("../type.zig").Type; |
| 41 | | 42 | |
| 42 | pub const TextBlock = Atom; | 43 | pub const TextBlock = Atom; |
| 43 | | 44 | |
| ... | @@ -220,7 +221,7 @@ managed_atoms: std.ArrayListUnmanaged(*Atom) = .{}, | ... | @@ -220,7 +221,7 @@ managed_atoms: std.ArrayListUnmanaged(*Atom) = .{}, |
| 220 | /// We store them here so that we can properly dispose of any allocated | 221 | /// We store them here so that we can properly dispose of any allocated |
| 221 | /// memory within the atom in the incremental linker. | 222 | /// memory within the atom in the incremental linker. |
| 222 | /// TODO consolidate this. | 223 | /// TODO consolidate this. |
| 223 | decls: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{}, | 224 | decls: std.AutoArrayHashMapUnmanaged(*Module.Decl, ?MatchingSection) = .{}, |
| 224 | | 225 | |
| 225 | /// Currently active Module.Decl. | 226 | /// Currently active Module.Decl. |
| 226 | /// TODO this might not be necessary if we figure out how to pass Module.Decl instance | 227 | /// TODO this might not be necessary if we figure out how to pass Module.Decl instance |
| ... | @@ -3450,7 +3451,7 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { | ... | @@ -3450,7 +3451,7 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { |
| 3450 | if (decl.link.macho.local_sym_index != 0) return; | 3451 | if (decl.link.macho.local_sym_index != 0) return; |
| 3451 | | 3452 | |
| 3452 | try self.locals.ensureUnusedCapacity(self.base.allocator, 1); | 3453 | try self.locals.ensureUnusedCapacity(self.base.allocator, 1); |
| 3453 | try self.decls.putNoClobber(self.base.allocator, decl, {}); | 3454 | try self.decls.putNoClobber(self.base.allocator, decl, null); |
| 3454 | | 3455 | |
| 3455 | if (self.locals_free_list.popOrNull()) |i| { | 3456 | if (self.locals_free_list.popOrNull()) |i| { |
| 3456 | log.debug("reusing symbol index {d} for {s}", .{ i, decl.name }); | 3457 | log.debug("reusing symbol index {d} for {s}", .{ i, decl.name }); |
| ... | @@ -3656,19 +3657,169 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -3656,19 +3657,169 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 3656 | try self.updateDeclExports(module, decl, decl_exports); | 3657 | try self.updateDeclExports(module, decl, decl_exports); |
| 3657 | } | 3658 | } |
| 3658 | | 3659 | |
| | 3660 | fn isElemTyPointer(ty: Type) bool { |
| | 3661 | switch (ty.zigTypeTag()) { |
| | 3662 | .Fn => return false, |
| | 3663 | .Pointer => return true, |
| | 3664 | .Array => { |
| | 3665 | const elem_ty = ty.elemType(); |
| | 3666 | return isElemTyPointer(elem_ty); |
| | 3667 | }, |
| | 3668 | .Struct, .Union => { |
| | 3669 | const len = ty.structFieldCount(); |
| | 3670 | var i: usize = 0; |
| | 3671 | while (i < len) : (i += 1) { |
| | 3672 | const field_ty = ty.structFieldType(i); |
| | 3673 | if (isElemTyPointer(field_ty)) return true; |
| | 3674 | } |
| | 3675 | return false; |
| | 3676 | }, |
| | 3677 | else => return false, |
| | 3678 | } |
| | 3679 | } |
| | 3680 | |
| | 3681 | fn getMatchingSectionDecl(self: *MachO, decl: *Module.Decl) !MatchingSection { |
| | 3682 | const code = decl.link.macho.code.items; |
| | 3683 | const alignment = decl.ty.abiAlignment(self.base.options.target); |
| | 3684 | const align_log_2 = math.log2(alignment); |
| | 3685 | const ty = decl.ty; |
| | 3686 | const zig_ty = ty.zigTypeTag(); |
| | 3687 | const val = decl.val; |
| | 3688 | const mode = self.base.options.optimize_mode; |
| | 3689 | const match: MatchingSection = blk: { |
| | 3690 | // TODO finish and audit this function |
| | 3691 | if (val.isUndefDeep()) { |
| | 3692 | if (mode == .ReleaseFast or mode == .ReleaseSmall) { |
| | 3693 | break :blk MatchingSection{ |
| | 3694 | .seg = self.data_segment_cmd_index.?, |
| | 3695 | .sect = self.bss_section_index.?, |
| | 3696 | }; |
| | 3697 | } |
| | 3698 | break :blk (try self.getMatchingSection(.{ |
| | 3699 | .segname = makeStaticString("__DATA"), |
| | 3700 | .sectname = makeStaticString("__data"), |
| | 3701 | .size = code.len, |
| | 3702 | .@"align" = align_log_2, |
| | 3703 | })).?; |
| | 3704 | } |
| | 3705 | |
| | 3706 | switch (zig_ty) { |
| | 3707 | .Fn => { |
| | 3708 | break :blk MatchingSection{ |
| | 3709 | .seg = self.text_segment_cmd_index.?, |
| | 3710 | .sect = self.text_section_index.?, |
| | 3711 | }; |
| | 3712 | }, |
| | 3713 | .Array => switch (val.tag()) { |
| | 3714 | .bytes => { |
| | 3715 | switch (ty.tag()) { |
| | 3716 | .array_u8_sentinel_0, |
| | 3717 | .const_slice_u8_sentinel_0, |
| | 3718 | .manyptr_const_u8_sentinel_0, |
| | 3719 | => { |
| | 3720 | break :blk (try self.getMatchingSection(.{ |
| | 3721 | .segname = makeStaticString("__TEXT"), |
| | 3722 | .sectname = makeStaticString("__cstring"), |
| | 3723 | .flags = macho.S_CSTRING_LITERALS, |
| | 3724 | .size = code.len, |
| | 3725 | .@"align" = align_log_2, |
| | 3726 | })).?; |
| | 3727 | }, |
| | 3728 | else => { |
| | 3729 | break :blk (try self.getMatchingSection(.{ |
| | 3730 | .segname = makeStaticString("__TEXT"), |
| | 3731 | .sectname = makeStaticString("__const"), |
| | 3732 | .size = code.len, |
| | 3733 | .@"align" = align_log_2, |
| | 3734 | })).?; |
| | 3735 | }, |
| | 3736 | } |
| | 3737 | }, |
| | 3738 | .array => { |
| | 3739 | if (isElemTyPointer(ty)) { |
| | 3740 | break :blk (try self.getMatchingSection(.{ |
| | 3741 | .segname = makeStaticString("__DATA_CONST"), |
| | 3742 | .sectname = makeStaticString("__const"), |
| | 3743 | .size = code.len, |
| | 3744 | .@"align" = 3, // TODO I think this should not be needed |
| | 3745 | })).?; |
| | 3746 | } else { |
| | 3747 | break :blk (try self.getMatchingSection(.{ |
| | 3748 | .segname = makeStaticString("__TEXT"), |
| | 3749 | .sectname = makeStaticString("__const"), |
| | 3750 | .size = code.len, |
| | 3751 | .@"align" = align_log_2, |
| | 3752 | })).?; |
| | 3753 | } |
| | 3754 | }, |
| | 3755 | else => { |
| | 3756 | break :blk (try self.getMatchingSection(.{ |
| | 3757 | .segname = makeStaticString("__TEXT"), |
| | 3758 | .sectname = makeStaticString("__const"), |
| | 3759 | .size = code.len, |
| | 3760 | .@"align" = align_log_2, |
| | 3761 | })).?; |
| | 3762 | }, |
| | 3763 | }, |
| | 3764 | .Pointer => { |
| | 3765 | if (val.castTag(.variable)) |_| { |
| | 3766 | break :blk MatchingSection{ |
| | 3767 | .seg = self.data_segment_cmd_index.?, |
| | 3768 | .sect = self.data_section_index.?, |
| | 3769 | }; |
| | 3770 | } else { |
| | 3771 | break :blk (try self.getMatchingSection(.{ |
| | 3772 | .segname = makeStaticString("__DATA_CONST"), |
| | 3773 | .sectname = makeStaticString("__const"), |
| | 3774 | .size = code.len, |
| | 3775 | .@"align" = align_log_2, |
| | 3776 | })).?; |
| | 3777 | } |
| | 3778 | }, |
| | 3779 | else => { |
| | 3780 | if (val.castTag(.variable)) |_| { |
| | 3781 | break :blk MatchingSection{ |
| | 3782 | .seg = self.data_segment_cmd_index.?, |
| | 3783 | .sect = self.data_section_index.?, |
| | 3784 | }; |
| | 3785 | } else { |
| | 3786 | break :blk (try self.getMatchingSection(.{ |
| | 3787 | .segname = makeStaticString("__TEXT"), |
| | 3788 | .sectname = makeStaticString("__const"), |
| | 3789 | .size = code.len, |
| | 3790 | .@"align" = align_log_2, |
| | 3791 | })).?; |
| | 3792 | } |
| | 3793 | }, |
| | 3794 | } |
| | 3795 | }; |
| | 3796 | const seg = self.load_commands.items[match.seg].segment; |
| | 3797 | const sect = seg.sections.items[match.sect]; |
| | 3798 | log.debug(" allocating atom in '{s},{s}' ({d},{d})", .{ |
| | 3799 | sect.segName(), |
| | 3800 | sect.sectName(), |
| | 3801 | match.seg, |
| | 3802 | match.sect, |
| | 3803 | }); |
| | 3804 | return match; |
| | 3805 | } |
| | 3806 | |
| 3659 | fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 { | 3807 | fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 { |
| 3660 | const required_alignment = decl.ty.abiAlignment(self.base.options.target); | 3808 | const required_alignment = decl.ty.abiAlignment(self.base.options.target); |
| 3661 | assert(decl.link.macho.local_sym_index != 0); // Caller forgot to call allocateDeclIndexes() | 3809 | assert(decl.link.macho.local_sym_index != 0); // Caller forgot to call allocateDeclIndexes() |
| 3662 | const symbol = &self.locals.items[decl.link.macho.local_sym_index]; | 3810 | const symbol = &self.locals.items[decl.link.macho.local_sym_index]; |
| 3663 | | 3811 | |
| | 3812 | const decl_ptr = self.decls.getPtr(decl).?; |
| | 3813 | if (decl_ptr.* == null) { |
| | 3814 | decl_ptr.* = try self.getMatchingSectionDecl(decl); |
| | 3815 | } |
| | 3816 | const match = decl_ptr.*.?; |
| | 3817 | |
| 3664 | if (decl.link.macho.size != 0) { | 3818 | if (decl.link.macho.size != 0) { |
| 3665 | const capacity = decl.link.macho.capacity(self.*); | 3819 | const capacity = decl.link.macho.capacity(self.*); |
| 3666 | const need_realloc = code_len > capacity or !mem.isAlignedGeneric(u64, symbol.n_value, required_alignment); | 3820 | const need_realloc = code_len > capacity or !mem.isAlignedGeneric(u64, symbol.n_value, required_alignment); |
| 3667 | if (need_realloc) { | 3821 | if (need_realloc) { |
| 3668 | const vaddr = try self.growAtom(&decl.link.macho, code_len, required_alignment, .{ | 3822 | const vaddr = try self.growAtom(&decl.link.macho, code_len, required_alignment, match); |
| 3669 | .seg = self.text_segment_cmd_index.?, | | |
| 3670 | .sect = self.text_section_index.?, | | |
| 3671 | }); | | |
| 3672 | | 3823 | |
| 3673 | log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ decl.name, symbol.n_value, vaddr }); | 3824 | log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ decl.name, symbol.n_value, vaddr }); |
| 3674 | | 3825 | |
| ... | @@ -3690,10 +3841,7 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 | ... | @@ -3690,10 +3841,7 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 |
| 3690 | | 3841 | |
| 3691 | symbol.n_value = vaddr; | 3842 | symbol.n_value = vaddr; |
| 3692 | } else if (code_len < decl.link.macho.size) { | 3843 | } else if (code_len < decl.link.macho.size) { |
| 3693 | self.shrinkAtom(&decl.link.macho, code_len, .{ | 3844 | self.shrinkAtom(&decl.link.macho, code_len, match); |
| 3694 | .seg = self.text_segment_cmd_index.?, | | |
| 3695 | .sect = self.text_section_index.?, | | |
| 3696 | }); | | |
| 3697 | } | 3845 | } |
| 3698 | decl.link.macho.size = code_len; | 3846 | decl.link.macho.size = code_len; |
| 3699 | decl.link.macho.dirty = true; | 3847 | decl.link.macho.dirty = true; |
| ... | @@ -3714,22 +3862,16 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 | ... | @@ -3714,22 +3862,16 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 |
| 3714 | defer self.base.allocator.free(decl_name); | 3862 | defer self.base.allocator.free(decl_name); |
| 3715 | | 3863 | |
| 3716 | const name_str_index = try self.makeString(decl_name); | 3864 | const name_str_index = try self.makeString(decl_name); |
| 3717 | const addr = try self.allocateAtom(&decl.link.macho, code_len, required_alignment, .{ | 3865 | const addr = try self.allocateAtom(&decl.link.macho, code_len, required_alignment, match); |
| 3718 | .seg = self.text_segment_cmd_index.?, | | |
| 3719 | .sect = self.text_section_index.?, | | |
| 3720 | }); | | |
| 3721 | | 3866 | |
| 3722 | log.debug("allocated atom for {s} at 0x{x}", .{ decl_name, addr }); | 3867 | log.debug("allocated atom for {s} at 0x{x}", .{ decl_name, addr }); |
| 3723 | | 3868 | |
| 3724 | errdefer self.freeAtom(&decl.link.macho, .{ | 3869 | errdefer self.freeAtom(&decl.link.macho, match); |
| 3725 | .seg = self.text_segment_cmd_index.?, | | |
| 3726 | .sect = self.text_section_index.?, | | |
| 3727 | }); | | |
| 3728 | | 3870 | |
| 3729 | symbol.* = .{ | 3871 | symbol.* = .{ |
| 3730 | .n_strx = name_str_index, | 3872 | .n_strx = name_str_index, |
| 3731 | .n_type = macho.N_SECT, | 3873 | .n_type = macho.N_SECT, |
| 3732 | .n_sect = @intCast(u8, self.text_section_index.?) + 1, | 3874 | .n_sect = @intCast(u8, self.section_ordinals.getIndex(match).?) + 1, |
| 3733 | .n_desc = 0, | 3875 | .n_desc = 0, |
| 3734 | .n_value = addr, | 3876 | .n_value = addr, |
| 3735 | }; | 3877 | }; |
| ... | @@ -3912,12 +4054,11 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { | ... | @@ -3912,12 +4054,11 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { |
| 3912 | if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl); | 4054 | if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl); |
| 3913 | } | 4055 | } |
| 3914 | log.debug("freeDecl {*}", .{decl}); | 4056 | log.debug("freeDecl {*}", .{decl}); |
| 3915 | _ = self.decls.swapRemove(decl); | 4057 | const kv = self.decls.fetchSwapRemove(decl); |
| | 4058 | if (kv.?.value) |match| { |
| | 4059 | self.freeAtom(&decl.link.macho, match); |
| | 4060 | } |
| 3916 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. | 4061 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. |
| 3917 | self.freeAtom(&decl.link.macho, .{ | | |
| 3918 | .seg = self.text_segment_cmd_index.?, | | |
| 3919 | .sect = self.text_section_index.?, | | |
| 3920 | }); | | |
| 3921 | if (decl.link.macho.local_sym_index != 0) { | 4062 | if (decl.link.macho.local_sym_index != 0) { |
| 3922 | self.locals_free_list.append(self.base.allocator, decl.link.macho.local_sym_index) catch {}; | 4063 | self.locals_free_list.append(self.base.allocator, decl.link.macho.local_sym_index) catch {}; |
| 3923 | | 4064 | |
| ... | @@ -3958,6 +4099,29 @@ pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 { | ... | @@ -3958,6 +4099,29 @@ pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 { |
| 3958 | return self.locals.items[decl.link.macho.local_sym_index].n_value; | 4099 | return self.locals.items[decl.link.macho.local_sym_index].n_value; |
| 3959 | } | 4100 | } |
| 3960 | | 4101 | |
| | 4102 | pub fn getDeclVAddrWithReloc(self: *MachO, decl: *const Module.Decl, offset: u64) !u64 { |
| | 4103 | assert(decl.link.macho.local_sym_index != 0); |
| | 4104 | assert(self.active_decl != null); |
| | 4105 | |
| | 4106 | const atom = &self.active_decl.?.link.macho; |
| | 4107 | try atom.relocs.append(self.base.allocator, .{ |
| | 4108 | .offset = @intCast(u32, offset), |
| | 4109 | .target = .{ .local = decl.link.macho.local_sym_index }, |
| | 4110 | .addend = 0, |
| | 4111 | .subtractor = null, |
| | 4112 | .pcrel = false, |
| | 4113 | .length = 3, |
| | 4114 | .@"type" = switch (self.base.options.target.cpu.arch) { |
| | 4115 | .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED), |
| | 4116 | .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED), |
| | 4117 | else => unreachable, |
| | 4118 | }, |
| | 4119 | }); |
| | 4120 | try atom.rebases.append(self.base.allocator, offset); |
| | 4121 | |
| | 4122 | return 0; |
| | 4123 | } |
| | 4124 | |
| 3961 | fn populateMissingMetadata(self: *MachO) !void { | 4125 | fn populateMissingMetadata(self: *MachO) !void { |
| 3962 | const cpu_arch = self.base.options.target.cpu.arch; | 4126 | const cpu_arch = self.base.options.target.cpu.arch; |
| 3963 | | 4127 | |