| ... | ... | @@ -27,6 +27,10 @@ const LoadCommand = union(enum) { |
| 27 | 27 | LinkeditData: macho.linkedit_data_command, |
| 28 | 28 | Symtab: macho.symtab_command, |
| 29 | 29 | Dysymtab: macho.dysymtab_command, |
| 30 | DyldInfo: macho.dyld_info_command, |
| 31 | Dylinker: macho.dylinker_command, |
| 32 | Dylib: macho.dylib_command, |
| 33 | EntryPoint: macho.entry_point_command, |
| 30 | 34 | |
| 31 | 35 | pub fn cmdsize(self: LoadCommand) u32 { |
| 32 | 36 | return switch (self) { |
| ... | ... | @@ -34,6 +38,10 @@ const LoadCommand = union(enum) { |
| 34 | 38 | .LinkeditData => |x| x.cmdsize, |
| 35 | 39 | .Symtab => |x| x.cmdsize, |
| 36 | 40 | .Dysymtab => |x| x.cmdsize, |
| 41 | .DyldInfo => |x| x.cmdsize, |
| 42 | .Dylinker => |x| x.cmdsize, |
| 43 | .Dylib => |x| x.cmdsize, |
| 44 | .EntryPoint => |x| x.cmdsize, |
| 37 | 45 | }; |
| 38 | 46 | } |
| 39 | 47 | |
| ... | ... | @@ -43,6 +51,10 @@ const LoadCommand = union(enum) { |
| 43 | 51 | .LinkeditData => |cmd| writeGeneric(cmd, file, offset), |
| 44 | 52 | .Symtab => |cmd| writeGeneric(cmd, file, offset), |
| 45 | 53 | .Dysymtab => |cmd| writeGeneric(cmd, file, offset), |
| 54 | .DyldInfo => |cmd| writeGeneric(cmd, file, offset), |
| 55 | .Dylinker => |cmd| writeGeneric(cmd, file, offset), |
| 56 | .Dylib => |cmd| writeGeneric(cmd, file, offset), |
| 57 | .EntryPoint => |cmd| writeGeneric(cmd, file, offset), |
| 46 | 58 | }; |
| 47 | 59 | } |
| 48 | 60 | |
| ... | ... | @@ -56,24 +68,42 @@ base: File, |
| 56 | 68 | |
| 57 | 69 | /// Table of all load commands |
| 58 | 70 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, |
| 71 | /// __PAGEZERO segment |
| 72 | pagezero_segment_cmd_index: ?u16 = null, |
| 73 | /// __TEXT segment |
| 74 | text_segment_cmd_index: ?u16 = null, |
| 75 | /// __DATA segment |
| 76 | data_segment_cmd_index: ?u16 = null, |
| 77 | /// __LINKEDIT segment |
| 78 | linkedit_segment_cmd_index: ?u16 = null, |
| 59 | 79 | segment_cmd_index: ?u16 = null, |
| 80 | /// Dyld info |
| 81 | dyld_info_cmd_index: ?u16 = null, |
| 82 | /// Symbol table |
| 60 | 83 | symtab_cmd_index: ?u16 = null, |
| 84 | /// Dynamic symbol table |
| 61 | 85 | dysymtab_cmd_index: ?u16 = null, |
| 86 | /// Path to dyld linker |
| 87 | dylinker_cmd_index: ?u16 = null, |
| 88 | /// Path to libSystem |
| 89 | libsystem_cmd_index: ?u16 = null, |
| 90 | /// Data-in-code section of __LINKEDIT segment |
| 62 | 91 | data_in_code_cmd_index: ?u16 = null, |
| 92 | /// Address to entry point function |
| 93 | function_starts_cmd_index: ?u16 = null, |
| 94 | /// Main/entry point |
| 95 | /// Specifies offset wrt __TEXT segment start address to the main entry point |
| 96 | /// of the binary. |
| 97 | main_cmd_index: ?u16 = null, |
| 63 | 98 | |
| 64 | 99 | /// Table of all sections |
| 65 | 100 | sections: std.ArrayListUnmanaged(macho.section_64) = .{}, |
| 66 | 101 | |
| 67 | | /// __TEXT segment sections |
| 102 | /// __TEXT,__text section |
| 68 | 103 | text_section_index: ?u16 = null, |
| 69 | | cstring_section_index: ?u16 = null, |
| 70 | | const_text_section_index: ?u16 = null, |
| 71 | | stubs_section_index: ?u16 = null, |
| 72 | | stub_helper_section_index: ?u16 = null, |
| 73 | 104 | |
| 74 | | /// __DATA segment sections |
| 105 | /// __DATA,__got section |
| 75 | 106 | got_section_index: ?u16 = null, |
| 76 | | const_data_section_index: ?u16 = null, |
| 77 | 107 | |
| 78 | 108 | entry_addr: ?u64 = null, |
| 79 | 109 | |
| ... | ... | @@ -734,11 +764,13 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 734 | 764 | .n_desc = 0, |
| 735 | 765 | .n_value = addr, |
| 736 | 766 | }; |
| 767 | self.offset_table.items[decl.link.macho.offset_table_index.?] = addr; |
| 737 | 768 | |
| 738 | 769 | // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated. |
| 739 | 770 | const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{}; |
| 740 | 771 | try self.updateDeclExports(module, decl, decl_exports); |
| 741 | 772 | try self.writeSymbol(decl.link.macho.symbol_table_index.?); |
| 773 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index.?); |
| 742 | 774 | |
| 743 | 775 | const text_section = self.sections.items[self.text_section_index.?]; |
| 744 | 776 | const section_offset = symbol.n_value - text_section.addr; |
| ... | ... | @@ -778,6 +810,25 @@ pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 { |
| 778 | 810 | } |
| 779 | 811 | |
| 780 | 812 | pub fn populateMissingMetadata(self: *MachO) !void { |
| 813 | if (self.pagezero_segment_cmd_index == null) { |
| 814 | self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 815 | try self.load_commands.append(self.base.allocator, .{ |
| 816 | .Segment = .{ |
| 817 | .cmd = macho.LC_SEGMENT_64, |
| 818 | .cmdsize = @sizeOf(macho.segment_command_64), |
| 819 | .segname = makeStaticString("__PAGEZERO"), |
| 820 | .vmaddr = 0, |
| 821 | .vmsize = 0x1000, // size always set to 4GB |
| 822 | .fileoff = 0, |
| 823 | .filesize = 0, |
| 824 | .maxprot = 0, |
| 825 | .initprot = 0, |
| 826 | .nsects = 0, |
| 827 | .flags = 0, |
| 828 | }, |
| 829 | }); |
| 830 | self.cmd_table_dirty = true; |
| 831 | } |
| 781 | 832 | if (self.segment_cmd_index == null) { |
| 782 | 833 | self.segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 783 | 834 | try self.load_commands.append(self.base.allocator, .{ |
| ... | ... | @@ -818,7 +869,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 818 | 869 | segment.nsects += 1; |
| 819 | 870 | |
| 820 | 871 | const file_size = self.base.options.program_code_size_hint; |
| 821 | | const off = @intCast(u32, self.findFreeSpace(file_size, 1)); |
| 872 | const off = @intCast(u32, self.findFreeSpace(file_size, 64)); |
| 822 | 873 | const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; |
| 823 | 874 | |
| 824 | 875 | log.debug("found __text section free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| ... | ... | @@ -829,7 +880,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 829 | 880 | .addr = 0, |
| 830 | 881 | .size = file_size, |
| 831 | 882 | .offset = off, |
| 832 | | .@"align" = 0x1000, |
| 883 | .@"align" = 12, |
| 833 | 884 | .reloff = 0, |
| 834 | 885 | .nreloc = 0, |
| 835 | 886 | .flags = flags, |
| ... | ... | @@ -843,6 +894,43 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 843 | 894 | segment.fileoff = off; |
| 844 | 895 | |
| 845 | 896 | log.debug("initial text section {}\n", .{self.sections.items[self.text_section_index.?]}); |
| 897 | log.debug("update segment {}\n", .{segment}); |
| 898 | } |
| 899 | if (self.got_section_index == null) { |
| 900 | self.got_section_index = @intCast(u16, self.sections.items.len); |
| 901 | const segment = &self.load_commands.items[self.segment_cmd_index.?].Segment; |
| 902 | const text_sect = &self.sections.items[self.text_section_index.?]; |
| 903 | segment.cmdsize += @sizeOf(macho.section_64); |
| 904 | segment.nsects += 1; |
| 905 | |
| 906 | const p_align = @sizeOf(u64); |
| 907 | const file_size = p_align * self.base.options.symbol_count_hint; |
| 908 | const off = @intCast(u32, self.findFreeSpace(file_size, p_align)); |
| 909 | |
| 910 | log.debug("found __got section free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 911 | |
| 912 | const padding_size = off - text_sect.offset - text_sect.size; |
| 913 | |
| 914 | try self.sections.append(self.base.allocator, .{ |
| 915 | .sectname = makeStaticString("__got"), |
| 916 | .segname = makeStaticString("__DATA"), |
| 917 | .addr = text_sect.addr + text_sect.size + padding_size, |
| 918 | .size = file_size, |
| 919 | .offset = off, |
| 920 | .@"align" = 3, |
| 921 | .reloff = 0, |
| 922 | .nreloc = 0, |
| 923 | .flags = macho.S_REGULAR, |
| 924 | .reserved1 = 0, |
| 925 | .reserved2 = 0, |
| 926 | .reserved3 = 0, |
| 927 | }); |
| 928 | |
| 929 | segment.vmsize += file_size + padding_size; |
| 930 | segment.filesize += file_size + padding_size; |
| 931 | |
| 932 | log.debug("initial got section {}\n", .{self.sections.items[self.got_section_index.?]}); |
| 933 | log.debug("update segment {}\n", .{segment}); |
| 846 | 934 | } |
| 847 | 935 | { |
| 848 | 936 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| ... | ... | @@ -875,8 +963,9 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 875 | 963 | const addr = blk: { |
| 876 | 964 | if (self.last_text_block) |last| { |
| 877 | 965 | const last_symbol = self.symbol_table.items[last.symbol_table_index.?]; |
| 878 | | const end_addr = last_symbol.n_value + last.size; |
| 879 | | const new_start_addr = mem.alignForwardGeneric(u64, end_addr, alignment); |
| 966 | const ideal_capacity = last.size * alloc_num / alloc_den; |
| 967 | const ideal_capacity_end_addr = last_symbol.n_value + ideal_capacity; |
| 968 | const new_start_addr = mem.alignForwardGeneric(u64, ideal_capacity_end_addr, alignment); |
| 880 | 969 | block_placement = last; |
| 881 | 970 | break :blk new_start_addr; |
| 882 | 971 | } else { |
| ... | ... | @@ -893,12 +982,6 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 893 | 982 | assert(needed_size <= text_capacity); // TODO handle growth |
| 894 | 983 | |
| 895 | 984 | self.last_text_block = text_block; |
| 896 | | text_section.size = needed_size; |
| 897 | | segment.vmsize = needed_size; |
| 898 | | segment.filesize = needed_size; |
| 899 | | if (alignment < text_section.@"align") { |
| 900 | | text_section.@"align" = @intCast(u32, alignment); |
| 901 | | } |
| 902 | 985 | } |
| 903 | 986 | text_block.size = new_block_size; |
| 904 | 987 | |
| ... | ... | @@ -961,11 +1044,8 @@ fn addPadding(self: *MachO, size: u64, file_offset: u64) !void { |
| 961 | 1044 | |
| 962 | 1045 | fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { |
| 963 | 1046 | const hdr_size: u64 = @sizeOf(macho.mach_header_64); |
| 964 | | if (start < hdr_size) |
| 965 | | return hdr_size; |
| 966 | | |
| 1047 | if (start < hdr_size) return hdr_size; |
| 967 | 1048 | const end = start + satMul(size, alloc_num) / alloc_den; |
| 968 | | |
| 969 | 1049 | { |
| 970 | 1050 | const off = @sizeOf(macho.mach_header_64); |
| 971 | 1051 | var tight_size: u64 = 0; |
| ... | ... | @@ -978,7 +1058,6 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { |
| 978 | 1058 | return test_end; |
| 979 | 1059 | } |
| 980 | 1060 | } |
| 981 | | |
| 982 | 1061 | for (self.sections.items) |section| { |
| 983 | 1062 | const increased_size = satMul(section.size, alloc_num) / alloc_den; |
| 984 | 1063 | const test_end = section.offset + increased_size; |
| ... | ... | @@ -986,7 +1065,6 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { |
| 986 | 1065 | return test_end; |
| 987 | 1066 | } |
| 988 | 1067 | } |
| 989 | | |
| 990 | 1068 | if (self.symtab_cmd_index) |symtab_index| { |
| 991 | 1069 | const symtab = self.load_commands.items[symtab_index].Symtab; |
| 992 | 1070 | { |
| ... | ... | @@ -1005,7 +1083,6 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { |
| 1005 | 1083 | } |
| 1006 | 1084 | } |
| 1007 | 1085 | } |
| 1008 | | |
| 1009 | 1086 | return null; |
| 1010 | 1087 | } |
| 1011 | 1088 | |
| ... | ... | @@ -1048,6 +1125,16 @@ fn writeSymbol(self: *MachO, index: usize) !void { |
| 1048 | 1125 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); |
| 1049 | 1126 | } |
| 1050 | 1127 | |
| 1128 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| 1129 | const sect = &self.sections.items[self.got_section_index.?]; |
| 1130 | const endian = self.base.options.target.cpu.arch.endian(); |
| 1131 | var buf: [@sizeOf(u64)]u8 = undefined; |
| 1132 | mem.writeInt(u64, &buf, self.offset_table.items[index], endian); |
| 1133 | const off = sect.offset + @sizeOf(u64) * index; |
| 1134 | log.debug("writing offset table entry 0x{x} at 0x{x}\n", .{ self.offset_table.items[index], off }); |
| 1135 | try self.base.file.?.pwriteAll(&buf, off); |
| 1136 | } |
| 1137 | |
| 1051 | 1138 | /// Writes Mach-O file header. |
| 1052 | 1139 | /// Should be invoked last as it needs up-to-date values of ncmds and sizeof_cmds bookkeeping |
| 1053 | 1140 | /// variables. |