| author | |
| committer | |
| log | 969f2cff8258fc91d7037704ddac4e6f4f037029 |
| tree | 12e10ee8516dde750fddf7c74b6bdf9e40a5adc1 |
| parent | 2962db333f43c8bb10a1e2ad4cdd19dfab26515b |
This allows segments to be moved around in the output file without
needing to reapply relocations until virtual address space is exhaused.6 files changed, 2659 insertions(+), 2679 deletions(-)
CMakeLists.txt+1| ... | @@ -561,6 +561,7 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -561,6 +561,7 @@ set(ZIG_STAGE2_SOURCES |
| 561 | src/libs/libunwind.zig | 561 | src/libs/libunwind.zig |
| 562 | src/link.zig | 562 | src/link.zig |
| 563 | src/link/C.zig | 563 | src/link/C.zig |
| 564 | src/link/Coff.zig | ||
| 564 | src/link/Dwarf.zig | 565 | src/link/Dwarf.zig |
| 565 | src/link/Elf.zig | 566 | src/link/Elf.zig |
| 566 | src/link/Elf/Archive.zig | 567 | src/link/Elf/Archive.zig |
src/Compilation.zig+11-29| ... | @@ -2718,35 +2718,17 @@ pub fn destroy(comp: *Compilation) void { | ... | @@ -2718,35 +2718,17 @@ pub fn destroy(comp: *Compilation) void { |
| 2718 | } | 2718 | } |
| 2719 | comp.crt_files.deinit(gpa); | 2719 | comp.crt_files.deinit(gpa); |
| 2720 | } | 2720 | } |
| 2721 | 2721 | if (comp.libcxx_static_lib) |*crt_file| crt_file.deinit(gpa); | |
| 2722 | if (comp.libunwind_static_lib) |*crt_file| { | 2722 | if (comp.libcxxabi_static_lib) |*crt_file| crt_file.deinit(gpa); |
| 2723 | crt_file.deinit(gpa); | 2723 | if (comp.libunwind_static_lib) |*crt_file| crt_file.deinit(gpa); |
| 2724 | } | 2724 | if (comp.tsan_lib) |*crt_file| crt_file.deinit(gpa); |
| 2725 | if (comp.libcxx_static_lib) |*crt_file| { | 2725 | if (comp.ubsan_rt_lib) |*crt_file| crt_file.deinit(gpa); |
| 2726 | crt_file.deinit(gpa); | 2726 | if (comp.ubsan_rt_obj) |*crt_file| crt_file.deinit(gpa); |
| 2727 | } | 2727 | if (comp.zigc_static_lib) |*crt_file| crt_file.deinit(gpa); |
| 2728 | if (comp.libcxxabi_static_lib) |*crt_file| { | 2728 | if (comp.compiler_rt_lib) |*crt_file| crt_file.deinit(gpa); |
| 2729 | crt_file.deinit(gpa); | 2729 | if (comp.compiler_rt_obj) |*crt_file| crt_file.deinit(gpa); |
| 2730 | } | 2730 | if (comp.compiler_rt_dyn_lib) |*crt_file| crt_file.deinit(gpa); |
| 2731 | if (comp.compiler_rt_lib) |*crt_file| { | 2731 | if (comp.fuzzer_lib) |*crt_file| crt_file.deinit(gpa); |
| 2732 | crt_file.deinit(gpa); | ||
| 2733 | } | ||
| 2734 | if (comp.compiler_rt_obj) |*crt_file| { | ||
| 2735 | crt_file.deinit(gpa); | ||
| 2736 | } | ||
| 2737 | if (comp.ubsan_rt_lib) |*crt_file| { | ||
| 2738 | crt_file.deinit(gpa); | ||
| 2739 | } | ||
| 2740 | if (comp.ubsan_rt_obj) |*crt_file| { | ||
| 2741 | crt_file.deinit(gpa); | ||
| 2742 | } | ||
| 2743 | if (comp.fuzzer_lib) |*crt_file| { | ||
| 2744 | crt_file.deinit(gpa); | ||
| 2745 | } | ||
| 2746 | |||
| 2747 | if (comp.zigc_static_lib) |*crt_file| { | ||
| 2748 | crt_file.deinit(gpa); | ||
| 2749 | } | ||
| 2750 | 2732 | ||
| 2751 | if (comp.glibc_so_files) |*glibc_file| { | 2733 | if (comp.glibc_so_files) |*glibc_file| { |
| 2752 | glibc_file.deinit(gpa); | 2734 | glibc_file.deinit(gpa); |
src/link.zig+1-1| ... | @@ -1265,7 +1265,7 @@ pub const File = struct { | ... | @@ -1265,7 +1265,7 @@ pub const File = struct { |
| 1265 | 1265 | ||
| 1266 | pub const Lld = @import("link/Lld.zig"); | 1266 | pub const Lld = @import("link/Lld.zig"); |
| 1267 | pub const C = @import("link/C.zig"); | 1267 | pub const C = @import("link/C.zig"); |
| 1268 | pub const Coff2 = @import("link/Coff2.zig"); | 1268 | pub const Coff2 = @import("link/Coff.zig"); |
| 1269 | pub const Elf = @import("link/Elf.zig"); | 1269 | pub const Elf = @import("link/Elf.zig"); |
| 1270 | pub const Elf2 = @import("link/Elf2.zig"); | 1270 | pub const Elf2 = @import("link/Elf2.zig"); |
| 1271 | pub const MachO = @import("link/MachO.zig"); | 1271 | pub const MachO = @import("link/MachO.zig"); |
src/link/Coff.zig created+2206| ... | @@ -0,0 +1,2206 @@ | ||
| 1 | base: link.File, | ||
| 2 | mf: MappedFile, | ||
| 3 | nodes: std.MultiArrayList(Node), | ||
| 4 | import_table: ImportTable, | ||
| 5 | strings: std.HashMapUnmanaged( | ||
| 6 | u32, | ||
| 7 | void, | ||
| 8 | std.hash_map.StringIndexContext, | ||
| 9 | std.hash_map.default_max_load_percentage, | ||
| 10 | ), | ||
| 11 | string_bytes: std.ArrayList(u8), | ||
| 12 | section_table: std.ArrayList(Symbol.Index), | ||
| 13 | symbol_table: std.ArrayList(Symbol), | ||
| 14 | globals: std.AutoArrayHashMapUnmanaged(GlobalName, Symbol.Index), | ||
| 15 | global_pending_index: u32, | ||
| 16 | navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index), | ||
| 17 | uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), | ||
| 18 | lazy: std.EnumArray(link.File.LazySymbol.Kind, struct { | ||
| 19 | map: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), | ||
| 20 | pending_index: u32, | ||
| 21 | }), | ||
| 22 | pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct { | ||
| 23 | alignment: InternPool.Alignment, | ||
| 24 | src_loc: Zcu.LazySrcLoc, | ||
| 25 | }), | ||
| 26 | relocs: std.ArrayList(Reloc), | ||
| 27 | /// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly. | ||
| 28 | entry_hack: Symbol.Index, | ||
| 29 | |||
| 30 | pub const default_file_alignment: u16 = 0x200; | ||
| 31 | pub const default_size_of_stack_reserve: u32 = 0x1000000; | ||
| 32 | pub const default_size_of_stack_commit: u32 = 0x1000; | ||
| 33 | pub const default_size_of_heap_reserve: u32 = 0x100000; | ||
| 34 | pub const default_size_of_heap_commit: u32 = 0x1000; | ||
| 35 | |||
| 36 | /// This is the start of a Portable Executable (PE) file. | ||
| 37 | /// It starts with a MS-DOS header followed by a MS-DOS stub program. | ||
| 38 | /// This data does not change so we include it as follows in all binaries. | ||
| 39 | /// | ||
| 40 | /// In this context, | ||
| 41 | /// A "paragraph" is 16 bytes. | ||
| 42 | /// A "page" is 512 bytes. | ||
| 43 | /// A "long" is 4 bytes. | ||
| 44 | /// A "word" is 2 bytes. | ||
| 45 | pub const msdos_stub: [120]u8 = .{ | ||
| 46 | 'M', 'Z', // Magic number. Stands for Mark Zbikowski (designer of the MS-DOS executable format). | ||
| 47 | 0x78, 0x00, // Number of bytes in the last page. This matches the size of this entire MS-DOS stub. | ||
| 48 | 0x01, 0x00, // Number of pages. | ||
| 49 | 0x00, 0x00, // Number of entries in the relocation table. | ||
| 50 | 0x04, 0x00, // The number of paragraphs taken up by the header. 4 * 16 = 64, which matches the header size (all bytes before the MS-DOS stub program). | ||
| 51 | 0x00, 0x00, // The number of paragraphs required by the program. | ||
| 52 | 0x00, 0x00, // The number of paragraphs requested by the program. | ||
| 53 | 0x00, 0x00, // Initial value for SS (relocatable segment address). | ||
| 54 | 0x00, 0x00, // Initial value for SP. | ||
| 55 | 0x00, 0x00, // Checksum. | ||
| 56 | 0x00, 0x00, // Initial value for IP. | ||
| 57 | 0x00, 0x00, // Initial value for CS (relocatable segment address). | ||
| 58 | 0x40, 0x00, // Absolute offset to relocation table. 64 matches the header size (all bytes before the MS-DOS stub program). | ||
| 59 | 0x00, 0x00, // Overlay number. Zero means this is the main executable. | ||
| 60 | } | ||
| 61 | // Reserved words. | ||
| 62 | ++ .{ 0x00, 0x00 } ** 4 | ||
| 63 | // OEM-related fields. | ||
| 64 | ++ .{ | ||
| 65 | 0x00, 0x00, // OEM identifier. | ||
| 66 | 0x00, 0x00, // OEM information. | ||
| 67 | } | ||
| 68 | // Reserved words. | ||
| 69 | ++ .{ 0x00, 0x00 } ** 10 | ||
| 70 | // Address of the PE header (a long). This matches the size of this entire MS-DOS stub, so that's the address of what's after this MS-DOS stub. | ||
| 71 | ++ .{ 0x78, 0x00, 0x00, 0x00 } | ||
| 72 | // What follows is a 16-bit x86 MS-DOS program of 7 instructions that prints the bytes after these instructions and then exits. | ||
| 73 | ++ .{ | ||
| 74 | // Set the value of the data segment to the same value as the code segment. | ||
| 75 | 0x0e, // push cs | ||
| 76 | 0x1f, // pop ds | ||
| 77 | // Set the DX register to the address of the message. | ||
| 78 | // If you count all bytes of these 7 instructions you get 14, so that's the address of what's after these instructions. | ||
| 79 | 0xba, 14, 0x00, // mov dx, 14 | ||
| 80 | // Set AH to the system call code for printing a message. | ||
| 81 | 0xb4, 0x09, // mov ah, 0x09 | ||
| 82 | // Perform the system call to print the message. | ||
| 83 | 0xcd, 0x21, // int 0x21 | ||
| 84 | // Set AH to 0x4c which is the system call code for exiting, and set AL to 0x01 which is the exit code. | ||
| 85 | 0xb8, 0x01, 0x4c, // mov ax, 0x4c01 | ||
| 86 | // Peform the system call to exit the program with exit code 1. | ||
| 87 | 0xcd, 0x21, // int 0x21 | ||
| 88 | } | ||
| 89 | // Message to print. | ||
| 90 | ++ "This program cannot be run in DOS mode.".* | ||
| 91 | // Message terminators. | ||
| 92 | ++ .{ | ||
| 93 | '$', // We do not pass a length to the print system call; the string is terminated by this character. | ||
| 94 | 0x00, 0x00, // Terminating zero bytes. | ||
| 95 | }; | ||
| 96 | |||
| 97 | pub const Node = union(enum) { | ||
| 98 | file, | ||
| 99 | header, | ||
| 100 | signature, | ||
| 101 | coff_header, | ||
| 102 | optional_header, | ||
| 103 | data_directories, | ||
| 104 | section_table, | ||
| 105 | section: Symbol.Index, | ||
| 106 | import_directory_table, | ||
| 107 | import_lookup_table: ImportTable.Index, | ||
| 108 | import_address_table: ImportTable.Index, | ||
| 109 | import_hint_name_table: ImportTable.Index, | ||
| 110 | global: GlobalMapIndex, | ||
| 111 | nav: NavMapIndex, | ||
| 112 | uav: UavMapIndex, | ||
| 113 | lazy_code: LazyMapRef.Index(.code), | ||
| 114 | lazy_const_data: LazyMapRef.Index(.const_data), | ||
| 115 | |||
| 116 | pub const GlobalMapIndex = enum(u32) { | ||
| 117 | _, | ||
| 118 | |||
| 119 | pub fn globalName(gmi: GlobalMapIndex, coff: *const Coff) GlobalName { | ||
| 120 | return coff.globals.keys()[@intFromEnum(gmi)]; | ||
| 121 | } | ||
| 122 | |||
| 123 | pub fn symbol(gmi: GlobalMapIndex, coff: *const Coff) Symbol.Index { | ||
| 124 | return coff.globals.values()[@intFromEnum(gmi)]; | ||
| 125 | } | ||
| 126 | }; | ||
| 127 | |||
| 128 | pub const NavMapIndex = enum(u32) { | ||
| 129 | _, | ||
| 130 | |||
| 131 | pub fn navIndex(nmi: NavMapIndex, coff: *const Coff) InternPool.Nav.Index { | ||
| 132 | return coff.navs.keys()[@intFromEnum(nmi)]; | ||
| 133 | } | ||
| 134 | |||
| 135 | pub fn symbol(nmi: NavMapIndex, coff: *const Coff) Symbol.Index { | ||
| 136 | return coff.navs.values()[@intFromEnum(nmi)]; | ||
| 137 | } | ||
| 138 | }; | ||
| 139 | |||
| 140 | pub const UavMapIndex = enum(u32) { | ||
| 141 | _, | ||
| 142 | |||
| 143 | pub fn uavValue(umi: UavMapIndex, coff: *const Coff) InternPool.Index { | ||
| 144 | return coff.uavs.keys()[@intFromEnum(umi)]; | ||
| 145 | } | ||
| 146 | |||
| 147 | pub fn symbol(umi: UavMapIndex, coff: *const Coff) Symbol.Index { | ||
| 148 | return coff.uavs.values()[@intFromEnum(umi)]; | ||
| 149 | } | ||
| 150 | }; | ||
| 151 | |||
| 152 | pub const LazyMapRef = struct { | ||
| 153 | kind: link.File.LazySymbol.Kind, | ||
| 154 | index: u32, | ||
| 155 | |||
| 156 | pub fn Index(comptime kind: link.File.LazySymbol.Kind) type { | ||
| 157 | return enum(u32) { | ||
| 158 | _, | ||
| 159 | |||
| 160 | pub fn ref(lmi: @This()) LazyMapRef { | ||
| 161 | return .{ .kind = kind, .index = @intFromEnum(lmi) }; | ||
| 162 | } | ||
| 163 | |||
| 164 | pub fn lazySymbol(lmi: @This(), coff: *const Coff) link.File.LazySymbol { | ||
| 165 | return lmi.ref().lazySymbol(coff); | ||
| 166 | } | ||
| 167 | |||
| 168 | pub fn symbol(lmi: @This(), coff: *const Coff) Symbol.Index { | ||
| 169 | return lmi.ref().symbol(coff); | ||
| 170 | } | ||
| 171 | }; | ||
| 172 | } | ||
| 173 | |||
| 174 | pub fn lazySymbol(lmr: LazyMapRef, coff: *const Coff) link.File.LazySymbol { | ||
| 175 | return .{ .kind = lmr.kind, .ty = coff.lazy.getPtrConst(lmr.kind).map.keys()[lmr.index] }; | ||
| 176 | } | ||
| 177 | |||
| 178 | pub fn symbol(lmr: LazyMapRef, coff: *const Coff) Symbol.Index { | ||
| 179 | return coff.lazy.getPtrConst(lmr.kind).map.values()[lmr.index]; | ||
| 180 | } | ||
| 181 | }; | ||
| 182 | |||
| 183 | pub const Tag = @typeInfo(Node).@"union".tag_type.?; | ||
| 184 | |||
| 185 | const known_count = @typeInfo(@TypeOf(known)).@"struct".fields.len; | ||
| 186 | const known = known: { | ||
| 187 | const Known = enum { | ||
| 188 | file, | ||
| 189 | header, | ||
| 190 | signature, | ||
| 191 | coff_header, | ||
| 192 | optional_header, | ||
| 193 | data_directories, | ||
| 194 | section_table, | ||
| 195 | }; | ||
| 196 | var mut_known: std.enums.EnumFieldStruct(Known, MappedFile.Node.Index, null) = undefined; | ||
| 197 | for (@typeInfo(Known).@"enum".fields) |field| | ||
| 198 | @field(mut_known, field.name) = @enumFromInt(field.value); | ||
| 199 | break :known mut_known; | ||
| 200 | }; | ||
| 201 | |||
| 202 | comptime { | ||
| 203 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Node) == 8); | ||
| 204 | } | ||
| 205 | }; | ||
| 206 | |||
| 207 | pub const DataDirectory = enum { | ||
| 208 | export_table, | ||
| 209 | import_table, | ||
| 210 | resorce_table, | ||
| 211 | exception_table, | ||
| 212 | certificate_table, | ||
| 213 | base_relocation_table, | ||
| 214 | debug, | ||
| 215 | architecture, | ||
| 216 | global_ptr, | ||
| 217 | tls_table, | ||
| 218 | load_config_table, | ||
| 219 | bound_import, | ||
| 220 | import_address_table, | ||
| 221 | delay_import_descriptor, | ||
| 222 | clr_runtime_header, | ||
| 223 | reserved, | ||
| 224 | |||
| 225 | pub const len = @typeInfo(DataDirectory).@"enum".fields.len; | ||
| 226 | }; | ||
| 227 | |||
| 228 | pub const ImportTable = struct { | ||
| 229 | ni: MappedFile.Node.Index, | ||
| 230 | entries: std.AutoArrayHashMapUnmanaged(void, Entry), | ||
| 231 | |||
| 232 | pub const Entry = struct { | ||
| 233 | import_lookup_table_ni: MappedFile.Node.Index, | ||
| 234 | import_address_table_si: Symbol.Index, | ||
| 235 | import_hint_name_table_ni: MappedFile.Node.Index, | ||
| 236 | len: u32, | ||
| 237 | hint_name_len: u32, | ||
| 238 | }; | ||
| 239 | |||
| 240 | const Adapter = struct { | ||
| 241 | coff: *Coff, | ||
| 242 | |||
| 243 | pub fn eql(adapter: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool { | ||
| 244 | const coff = adapter.coff; | ||
| 245 | const dll_name = coff.import_table.entries.values()[rhs_index] | ||
| 246 | .import_hint_name_table_ni.sliceConst(&coff.mf); | ||
| 247 | return std.mem.startsWith(u8, dll_name, lhs_key) and | ||
| 248 | std.mem.startsWith(u8, dll_name[lhs_key.len..], ".dll\x00"); | ||
| 249 | } | ||
| 250 | |||
| 251 | pub fn hash(_: Adapter, key: []const u8) u32 { | ||
| 252 | assert(std.mem.indexOfScalar(u8, key, 0) == null); | ||
| 253 | return std.array_hash_map.hashString(key); | ||
| 254 | } | ||
| 255 | }; | ||
| 256 | |||
| 257 | pub const Index = enum(u32) { | ||
| 258 | _, | ||
| 259 | |||
| 260 | pub fn get(import_index: ImportTable.Index, coff: *Coff) *Entry { | ||
| 261 | return &coff.import_table.entries.values()[@intFromEnum(import_index)]; | ||
| 262 | } | ||
| 263 | }; | ||
| 264 | }; | ||
| 265 | |||
| 266 | pub const String = enum(u32) { | ||
| 267 | _, | ||
| 268 | |||
| 269 | pub const Optional = enum(u32) { | ||
| 270 | none = std.math.maxInt(u32), | ||
| 271 | _, | ||
| 272 | |||
| 273 | pub fn unwrap(os: String.Optional) ?String { | ||
| 274 | return switch (os) { | ||
| 275 | else => |s| @enumFromInt(@intFromEnum(s)), | ||
| 276 | .none => null, | ||
| 277 | }; | ||
| 278 | } | ||
| 279 | |||
| 280 | pub fn toSlice(os: String.Optional, coff: *Coff) ?[:0]const u8 { | ||
| 281 | return (os.unwrap() orelse return null).toSlice(coff); | ||
| 282 | } | ||
| 283 | }; | ||
| 284 | |||
| 285 | pub fn toSlice(s: String, coff: *Coff) [:0]const u8 { | ||
| 286 | const slice = coff.string_bytes.items[@intFromEnum(s)..]; | ||
| 287 | return slice[0..std.mem.indexOfScalar(u8, slice, 0).? :0]; | ||
| 288 | } | ||
| 289 | |||
| 290 | pub fn toOptional(s: String) String.Optional { | ||
| 291 | return @enumFromInt(@intFromEnum(s)); | ||
| 292 | } | ||
| 293 | }; | ||
| 294 | |||
| 295 | pub const GlobalName = struct { name: String, lib_name: String.Optional }; | ||
| 296 | |||
| 297 | pub const Symbol = struct { | ||
| 298 | ni: MappedFile.Node.Index, | ||
| 299 | rva: u32, | ||
| 300 | size: u32, | ||
| 301 | /// Relocations contained within this symbol | ||
| 302 | loc_relocs: Reloc.Index, | ||
| 303 | /// Relocations targeting this symbol | ||
| 304 | target_relocs: Reloc.Index, | ||
| 305 | section_number: SectionNumber, | ||
| 306 | unused0: u32 = 0, | ||
| 307 | unused1: u32 = 0, | ||
| 308 | unused2: u16 = 0, | ||
| 309 | |||
| 310 | pub const SectionNumber = enum(i16) { | ||
| 311 | UNDEFINED = 0, | ||
| 312 | ABSOLUTE = -1, | ||
| 313 | DEBUG = -2, | ||
| 314 | _, | ||
| 315 | |||
| 316 | fn toIndex(sn: SectionNumber) u15 { | ||
| 317 | return @intCast(@intFromEnum(sn) - 1); | ||
| 318 | } | ||
| 319 | |||
| 320 | pub fn symbol(sn: SectionNumber, coff: *const Coff) Symbol.Index { | ||
| 321 | return coff.section_table.items[sn.toIndex()]; | ||
| 322 | } | ||
| 323 | |||
| 324 | pub fn header(sn: SectionNumber, coff: *Coff) *std.coff.SectionHeader { | ||
| 325 | return &coff.sectionTableSlice()[sn.toIndex()]; | ||
| 326 | } | ||
| 327 | }; | ||
| 328 | |||
| 329 | pub const Index = enum(u32) { | ||
| 330 | null, | ||
| 331 | data, | ||
| 332 | idata, | ||
| 333 | rdata, | ||
| 334 | text, | ||
| 335 | _, | ||
| 336 | |||
| 337 | const known_count = @typeInfo(Index).@"enum".fields.len; | ||
| 338 | |||
| 339 | pub fn get(si: Symbol.Index, coff: *Coff) *Symbol { | ||
| 340 | return &coff.symbol_table.items[@intFromEnum(si)]; | ||
| 341 | } | ||
| 342 | |||
| 343 | pub fn node(si: Symbol.Index, coff: *Coff) MappedFile.Node.Index { | ||
| 344 | const ni = si.get(coff).ni; | ||
| 345 | assert(ni != .none); | ||
| 346 | return ni; | ||
| 347 | } | ||
| 348 | |||
| 349 | pub fn flushMoved(si: Symbol.Index, coff: *Coff) void { | ||
| 350 | const sym = si.get(coff); | ||
| 351 | sym.rva = coff.computeNodeRva(sym.ni); | ||
| 352 | if (si == coff.entry_hack) { | ||
| 353 | @branchHint(.unlikely); | ||
| 354 | coff.targetStore(&coff.optionalHeaderStandardPtr().address_of_entry_point, sym.rva); | ||
| 355 | } | ||
| 356 | si.applyLocationRelocs(coff); | ||
| 357 | si.applyTargetRelocs(coff); | ||
| 358 | } | ||
| 359 | |||
| 360 | pub fn applyLocationRelocs(si: Symbol.Index, coff: *Coff) void { | ||
| 361 | for (coff.relocs.items[@intFromEnum(si.get(coff).loc_relocs)..]) |*reloc| { | ||
| 362 | if (reloc.loc != si) break; | ||
| 363 | reloc.apply(coff); | ||
| 364 | } | ||
| 365 | } | ||
| 366 | |||
| 367 | pub fn applyTargetRelocs(si: Symbol.Index, coff: *Coff) void { | ||
| 368 | var ri = si.get(coff).target_relocs; | ||
| 369 | while (ri != .none) { | ||
| 370 | const reloc = ri.get(coff); | ||
| 371 | assert(reloc.target == si); | ||
| 372 | reloc.apply(coff); | ||
| 373 | ri = reloc.next; | ||
| 374 | } | ||
| 375 | } | ||
| 376 | |||
| 377 | pub fn deleteLocationRelocs(si: Symbol.Index, coff: *Coff) void { | ||
| 378 | const sym = si.get(coff); | ||
| 379 | for (coff.relocs.items[@intFromEnum(sym.loc_relocs)..]) |*reloc| { | ||
| 380 | if (reloc.loc != si) break; | ||
| 381 | reloc.delete(coff); | ||
| 382 | } | ||
| 383 | sym.loc_relocs = .none; | ||
| 384 | } | ||
| 385 | }; | ||
| 386 | |||
| 387 | comptime { | ||
| 388 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 32); | ||
| 389 | } | ||
| 390 | }; | ||
| 391 | |||
| 392 | pub const Reloc = extern struct { | ||
| 393 | type: Reloc.Type, | ||
| 394 | prev: Reloc.Index, | ||
| 395 | next: Reloc.Index, | ||
| 396 | loc: Symbol.Index, | ||
| 397 | target: Symbol.Index, | ||
| 398 | unused: u32, | ||
| 399 | offset: u64, | ||
| 400 | addend: i64, | ||
| 401 | |||
| 402 | pub const Type = extern union { | ||
| 403 | AMD64: std.coff.IMAGE.REL.AMD64, | ||
| 404 | ARM: std.coff.IMAGE.REL.ARM, | ||
| 405 | ARM64: std.coff.IMAGE.REL.ARM64, | ||
| 406 | SH: std.coff.IMAGE.REL.SH, | ||
| 407 | PPC: std.coff.IMAGE.REL.PPC, | ||
| 408 | I386: std.coff.IMAGE.REL.I386, | ||
| 409 | IA64: std.coff.IMAGE.REL.IA64, | ||
| 410 | MIPS: std.coff.IMAGE.REL.MIPS, | ||
| 411 | M32R: std.coff.IMAGE.REL.M32R, | ||
| 412 | }; | ||
| 413 | |||
| 414 | pub const Index = enum(u32) { | ||
| 415 | none = std.math.maxInt(u32), | ||
| 416 | _, | ||
| 417 | |||
| 418 | pub fn get(si: Reloc.Index, coff: *Coff) *Reloc { | ||
| 419 | return &coff.relocs.items[@intFromEnum(si)]; | ||
| 420 | } | ||
| 421 | }; | ||
| 422 | |||
| 423 | pub fn apply(reloc: *const Reloc, coff: *Coff) void { | ||
| 424 | const loc_sym = reloc.loc.get(coff); | ||
| 425 | switch (loc_sym.ni) { | ||
| 426 | .none => return, | ||
| 427 | else => |ni| if (ni.hasMoved(&coff.mf)) return, | ||
| 428 | } | ||
| 429 | const target_sym = reloc.target.get(coff); | ||
| 430 | switch (target_sym.ni) { | ||
| 431 | .none => return, | ||
| 432 | else => |ni| if (ni.hasMoved(&coff.mf)) return, | ||
| 433 | } | ||
| 434 | const loc_slice = loc_sym.ni.slice(&coff.mf)[@intCast(reloc.offset)..]; | ||
| 435 | const target_rva = target_sym.rva +% @as(u64, @bitCast(reloc.addend)); | ||
| 436 | const target_endian = coff.targetEndian(); | ||
| 437 | switch (coff.targetLoad(&coff.headerPtr().machine)) { | ||
| 438 | else => |machine| @panic(@tagName(machine)), | ||
| 439 | .AMD64 => switch (reloc.type.AMD64) { | ||
| 440 | else => |kind| @panic(@tagName(kind)), | ||
| 441 | .ABSOLUTE => {}, | ||
| 442 | .ADDR64 => std.mem.writeInt( | ||
| 443 | u64, | ||
| 444 | loc_slice[0..8], | ||
| 445 | coff.optionalHeaderField(.image_base) + target_rva, | ||
| 446 | target_endian, | ||
| 447 | ), | ||
| 448 | .ADDR32 => std.mem.writeInt( | ||
| 449 | u32, | ||
| 450 | loc_slice[0..4], | ||
| 451 | @intCast(coff.optionalHeaderField(.image_base) + target_rva), | ||
| 452 | target_endian, | ||
| 453 | ), | ||
| 454 | .ADDR32NB => std.mem.writeInt( | ||
| 455 | u32, | ||
| 456 | loc_slice[0..4], | ||
| 457 | @intCast(target_rva), | ||
| 458 | target_endian, | ||
| 459 | ), | ||
| 460 | .REL32 => std.mem.writeInt( | ||
| 461 | i32, | ||
| 462 | loc_slice[0..4], | ||
| 463 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 4)))), | ||
| 464 | target_endian, | ||
| 465 | ), | ||
| 466 | .REL32_1 => std.mem.writeInt( | ||
| 467 | i32, | ||
| 468 | loc_slice[0..4], | ||
| 469 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 5)))), | ||
| 470 | target_endian, | ||
| 471 | ), | ||
| 472 | .REL32_2 => std.mem.writeInt( | ||
| 473 | i32, | ||
| 474 | loc_slice[0..4], | ||
| 475 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 6)))), | ||
| 476 | target_endian, | ||
| 477 | ), | ||
| 478 | .REL32_3 => std.mem.writeInt( | ||
| 479 | i32, | ||
| 480 | loc_slice[0..4], | ||
| 481 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 7)))), | ||
| 482 | target_endian, | ||
| 483 | ), | ||
| 484 | .REL32_4 => std.mem.writeInt( | ||
| 485 | i32, | ||
| 486 | loc_slice[0..4], | ||
| 487 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 8)))), | ||
| 488 | target_endian, | ||
| 489 | ), | ||
| 490 | .REL32_5 => std.mem.writeInt( | ||
| 491 | i32, | ||
| 492 | loc_slice[0..4], | ||
| 493 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 9)))), | ||
| 494 | target_endian, | ||
| 495 | ), | ||
| 496 | }, | ||
| 497 | .I386 => switch (reloc.type.I386) { | ||
| 498 | else => |kind| @panic(@tagName(kind)), | ||
| 499 | .ABSOLUTE => {}, | ||
| 500 | .DIR16 => std.mem.writeInt( | ||
| 501 | u16, | ||
| 502 | loc_slice[0..2], | ||
| 503 | @intCast(coff.optionalHeaderField(.image_base) + target_rva), | ||
| 504 | target_endian, | ||
| 505 | ), | ||
| 506 | .REL16 => std.mem.writeInt( | ||
| 507 | i16, | ||
| 508 | loc_slice[0..2], | ||
| 509 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 2)))), | ||
| 510 | target_endian, | ||
| 511 | ), | ||
| 512 | .DIR32 => std.mem.writeInt( | ||
| 513 | u32, | ||
| 514 | loc_slice[0..4], | ||
| 515 | @intCast(coff.optionalHeaderField(.image_base) + target_rva), | ||
| 516 | target_endian, | ||
| 517 | ), | ||
| 518 | .DIR32NB => std.mem.writeInt( | ||
| 519 | u32, | ||
| 520 | loc_slice[0..4], | ||
| 521 | @intCast(target_rva), | ||
| 522 | target_endian, | ||
| 523 | ), | ||
| 524 | .REL32 => std.mem.writeInt( | ||
| 525 | i32, | ||
| 526 | loc_slice[0..4], | ||
| 527 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 4)))), | ||
| 528 | target_endian, | ||
| 529 | ), | ||
| 530 | }, | ||
| 531 | } | ||
| 532 | } | ||
| 533 | |||
| 534 | pub fn delete(reloc: *Reloc, coff: *Coff) void { | ||
| 535 | switch (reloc.prev) { | ||
| 536 | .none => { | ||
| 537 | const target = reloc.target.get(coff); | ||
| 538 | assert(target.target_relocs.get(coff) == reloc); | ||
| 539 | target.target_relocs = reloc.next; | ||
| 540 | }, | ||
| 541 | else => |prev| prev.get(coff).next = reloc.next, | ||
| 542 | } | ||
| 543 | switch (reloc.next) { | ||
| 544 | .none => {}, | ||
| 545 | else => |next| next.get(coff).prev = reloc.prev, | ||
| 546 | } | ||
| 547 | reloc.* = undefined; | ||
| 548 | } | ||
| 549 | |||
| 550 | comptime { | ||
| 551 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Reloc) == 40); | ||
| 552 | } | ||
| 553 | }; | ||
| 554 | |||
| 555 | pub fn open( | ||
| 556 | arena: std.mem.Allocator, | ||
| 557 | comp: *Compilation, | ||
| 558 | path: std.Build.Cache.Path, | ||
| 559 | options: link.File.OpenOptions, | ||
| 560 | ) !*Coff { | ||
| 561 | return create(arena, comp, path, options); | ||
| 562 | } | ||
| 563 | pub fn createEmpty( | ||
| 564 | arena: std.mem.Allocator, | ||
| 565 | comp: *Compilation, | ||
| 566 | path: std.Build.Cache.Path, | ||
| 567 | options: link.File.OpenOptions, | ||
| 568 | ) !*Coff { | ||
| 569 | return create(arena, comp, path, options); | ||
| 570 | } | ||
| 571 | fn create( | ||
| 572 | arena: std.mem.Allocator, | ||
| 573 | comp: *Compilation, | ||
| 574 | path: std.Build.Cache.Path, | ||
| 575 | options: link.File.OpenOptions, | ||
| 576 | ) !*Coff { | ||
| 577 | const target = &comp.root_mod.resolved_target.result; | ||
| 578 | assert(target.ofmt == .coff); | ||
| 579 | if (target.cpu.arch.endian() != comptime targetEndian(undefined)) | ||
| 580 | return error.UnsupportedCOFFArchitecture; | ||
| 581 | const is_image = switch (comp.config.output_mode) { | ||
| 582 | .Exe => true, | ||
| 583 | .Lib => switch (comp.config.link_mode) { | ||
| 584 | .static => false, | ||
| 585 | .dynamic => true, | ||
| 586 | }, | ||
| 587 | .Obj => false, | ||
| 588 | }; | ||
| 589 | const machine = target.toCoffMachine(); | ||
| 590 | const timestamp: u32 = if (options.repro) 0 else @truncate(@as(u64, @bitCast(std.time.timestamp()))); | ||
| 591 | const major_subsystem_version = options.major_subsystem_version orelse 6; | ||
| 592 | const minor_subsystem_version = options.minor_subsystem_version orelse 0; | ||
| 593 | const magic: std.coff.OptionalHeader.Magic = switch (target.ptrBitWidth()) { | ||
| 594 | 0...32 => .PE32, | ||
| 595 | 33...64 => .@"PE32+", | ||
| 596 | else => return error.UnsupportedCOFFArchitecture, | ||
| 597 | }; | ||
| 598 | const section_align: std.mem.Alignment = switch (machine) { | ||
| 599 | .AMD64, .I386 => @enumFromInt(12), | ||
| 600 | .SH3, .SH3DSP, .SH4, .SH5 => @enumFromInt(12), | ||
| 601 | .MIPS16, .MIPSFPU, .MIPSFPU16, .WCEMIPSV2 => @enumFromInt(12), | ||
| 602 | .POWERPC, .POWERPCFP => @enumFromInt(12), | ||
| 603 | .ALPHA, .ALPHA64 => @enumFromInt(13), | ||
| 604 | .IA64 => @enumFromInt(13), | ||
| 605 | .ARM => @enumFromInt(12), | ||
| 606 | else => return error.UnsupportedCOFFArchitecture, | ||
| 607 | }; | ||
| 608 | |||
| 609 | const coff = try arena.create(Coff); | ||
| 610 | const file = try path.root_dir.handle.createFile(path.sub_path, .{ | ||
| 611 | .read = true, | ||
| 612 | .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode), | ||
| 613 | }); | ||
| 614 | errdefer file.close(); | ||
| 615 | coff.* = .{ | ||
| 616 | .base = .{ | ||
| 617 | .tag = .coff2, | ||
| 618 | |||
| 619 | .comp = comp, | ||
| 620 | .emit = path, | ||
| 621 | |||
| 622 | .file = file, | ||
| 623 | .gc_sections = false, | ||
| 624 | .print_gc_sections = false, | ||
| 625 | .build_id = .none, | ||
| 626 | .allow_shlib_undefined = false, | ||
| 627 | .stack_size = 0, | ||
| 628 | }, | ||
| 629 | .mf = try .init(file, comp.gpa), | ||
| 630 | .nodes = .empty, | ||
| 631 | .import_table = .{ | ||
| 632 | .ni = .none, | ||
| 633 | .entries = .empty, | ||
| 634 | }, | ||
| 635 | .strings = .empty, | ||
| 636 | .string_bytes = .empty, | ||
| 637 | .section_table = .empty, | ||
| 638 | .symbol_table = .empty, | ||
| 639 | .globals = .empty, | ||
| 640 | .global_pending_index = 0, | ||
| 641 | .navs = .empty, | ||
| 642 | .uavs = .empty, | ||
| 643 | .lazy = .initFill(.{ | ||
| 644 | .map = .empty, | ||
| 645 | .pending_index = 0, | ||
| 646 | }), | ||
| 647 | .pending_uavs = .empty, | ||
| 648 | .relocs = .empty, | ||
| 649 | .entry_hack = .null, | ||
| 650 | }; | ||
| 651 | errdefer coff.deinit(); | ||
| 652 | |||
| 653 | try coff.initHeaders( | ||
| 654 | is_image, | ||
| 655 | machine, | ||
| 656 | timestamp, | ||
| 657 | major_subsystem_version, | ||
| 658 | minor_subsystem_version, | ||
| 659 | magic, | ||
| 660 | section_align, | ||
| 661 | ); | ||
| 662 | return coff; | ||
| 663 | } | ||
| 664 | |||
| 665 | pub fn deinit(coff: *Coff) void { | ||
| 666 | const gpa = coff.base.comp.gpa; | ||
| 667 | coff.mf.deinit(gpa); | ||
| 668 | coff.nodes.deinit(gpa); | ||
| 669 | coff.import_table.entries.deinit(gpa); | ||
| 670 | coff.strings.deinit(gpa); | ||
| 671 | coff.string_bytes.deinit(gpa); | ||
| 672 | coff.section_table.deinit(gpa); | ||
| 673 | coff.symbol_table.deinit(gpa); | ||
| 674 | coff.globals.deinit(gpa); | ||
| 675 | coff.navs.deinit(gpa); | ||
| 676 | coff.uavs.deinit(gpa); | ||
| 677 | for (&coff.lazy.values) |*lazy| lazy.map.deinit(gpa); | ||
| 678 | coff.pending_uavs.deinit(gpa); | ||
| 679 | coff.relocs.deinit(gpa); | ||
| 680 | coff.* = undefined; | ||
| 681 | } | ||
| 682 | |||
| 683 | fn initHeaders( | ||
| 684 | coff: *Coff, | ||
| 685 | is_image: bool, | ||
| 686 | machine: std.coff.IMAGE.FILE.MACHINE, | ||
| 687 | timestamp: u32, | ||
| 688 | major_subsystem_version: u16, | ||
| 689 | minor_subsystem_version: u16, | ||
| 690 | magic: std.coff.OptionalHeader.Magic, | ||
| 691 | section_align: std.mem.Alignment, | ||
| 692 | ) !void { | ||
| 693 | const comp = coff.base.comp; | ||
| 694 | const gpa = comp.gpa; | ||
| 695 | const file_align: std.mem.Alignment = comptime .fromByteUnits(default_file_alignment); | ||
| 696 | const target_endian = coff.targetEndian(); | ||
| 697 | |||
| 698 | const optional_header_size: u16 = if (is_image) switch (magic) { | ||
| 699 | _ => unreachable, | ||
| 700 | inline else => |ct_magic| @sizeOf(@field(std.coff.OptionalHeader, @tagName(ct_magic))), | ||
| 701 | } else 0; | ||
| 702 | const data_directories_size: u16 = if (is_image) | ||
| 703 | @sizeOf(std.coff.ImageDataDirectory) * DataDirectory.len | ||
| 704 | else | ||
| 705 | 0; | ||
| 706 | |||
| 707 | try coff.nodes.ensureTotalCapacity(gpa, Node.known_count); | ||
| 708 | coff.nodes.appendAssumeCapacity(.file); | ||
| 709 | |||
| 710 | const header_ni = Node.known.header; | ||
| 711 | assert(header_ni == try coff.mf.addOnlyChildNode(gpa, .root, .{ | ||
| 712 | .alignment = coff.mf.flags.block_size, | ||
| 713 | .fixed = true, | ||
| 714 | })); | ||
| 715 | coff.nodes.appendAssumeCapacity(.header); | ||
| 716 | |||
| 717 | const signature_ni = Node.known.signature; | ||
| 718 | assert(signature_ni == try coff.mf.addOnlyChildNode(gpa, header_ni, .{ | ||
| 719 | .size = (if (is_image) msdos_stub.len else 0) + "PE\x00\x00".len, | ||
| 720 | .alignment = .@"4", | ||
| 721 | .fixed = true, | ||
| 722 | })); | ||
| 723 | coff.nodes.appendAssumeCapacity(.signature); | ||
| 724 | { | ||
| 725 | const signature_slice = signature_ni.slice(&coff.mf); | ||
| 726 | if (is_image) @memcpy(signature_slice[0..msdos_stub.len], &msdos_stub); | ||
| 727 | @memcpy(signature_slice[signature_slice.len - 4 ..], "PE\x00\x00"); | ||
| 728 | } | ||
| 729 | |||
| 730 | const coff_header_ni = Node.known.coff_header; | ||
| 731 | assert(coff_header_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ | ||
| 732 | .size = @sizeOf(std.coff.Header), | ||
| 733 | .alignment = .@"4", | ||
| 734 | .fixed = true, | ||
| 735 | })); | ||
| 736 | coff.nodes.appendAssumeCapacity(.coff_header); | ||
| 737 | { | ||
| 738 | const coff_header = coff.headerPtr(); | ||
| 739 | coff_header.* = .{ | ||
| 740 | .machine = machine, | ||
| 741 | .number_of_sections = 0, | ||
| 742 | .time_date_stamp = timestamp, | ||
| 743 | .pointer_to_symbol_table = 0, | ||
| 744 | .number_of_symbols = 0, | ||
| 745 | .size_of_optional_header = optional_header_size + data_directories_size, | ||
| 746 | .flags = .{ | ||
| 747 | .RELOCS_STRIPPED = is_image, | ||
| 748 | .EXECUTABLE_IMAGE = is_image, | ||
| 749 | .DEBUG_STRIPPED = true, | ||
| 750 | .@"32BIT_MACHINE" = magic == .PE32, | ||
| 751 | .LARGE_ADDRESS_AWARE = magic == .@"PE32+", | ||
| 752 | .DLL = comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic, | ||
| 753 | }, | ||
| 754 | }; | ||
| 755 | if (target_endian != native_endian) std.mem.byteSwapAllFields(std.coff.Header, coff_header); | ||
| 756 | } | ||
| 757 | |||
| 758 | const optional_header_ni = Node.known.optional_header; | ||
| 759 | assert(optional_header_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ | ||
| 760 | .size = optional_header_size, | ||
| 761 | .alignment = .@"4", | ||
| 762 | .fixed = true, | ||
| 763 | })); | ||
| 764 | coff.nodes.appendAssumeCapacity(.optional_header); | ||
| 765 | coff.targetStore(&coff.optionalHeaderStandardPtr().magic, magic); | ||
| 766 | if (is_image) switch (coff.optionalHeaderPtr()) { | ||
| 767 | .PE32 => |optional_header| { | ||
| 768 | optional_header.* = .{ | ||
| 769 | .standard = .{ | ||
| 770 | .magic = .PE32, | ||
| 771 | .major_linker_version = 0, | ||
| 772 | .minor_linker_version = 0, | ||
| 773 | .size_of_code = 0, | ||
| 774 | .size_of_initialized_data = 0, | ||
| 775 | .size_of_uninitialized_data = 0, | ||
| 776 | .address_of_entry_point = 0, | ||
| 777 | .base_of_code = 0, | ||
| 778 | }, | ||
| 779 | .base_of_data = 0, | ||
| 780 | .image_base = switch (coff.base.comp.config.output_mode) { | ||
| 781 | .Exe => 0x400000, | ||
| 782 | .Lib => switch (coff.base.comp.config.link_mode) { | ||
| 783 | .static => 0, | ||
| 784 | .dynamic => 0x10000000, | ||
| 785 | }, | ||
| 786 | .Obj => 0, | ||
| 787 | }, | ||
| 788 | .section_alignment = @intCast(section_align.toByteUnits()), | ||
| 789 | .file_alignment = @intCast(file_align.toByteUnits()), | ||
| 790 | .major_operating_system_version = 6, | ||
| 791 | .minor_operating_system_version = 0, | ||
| 792 | .major_image_version = 0, | ||
| 793 | .minor_image_version = 0, | ||
| 794 | .major_subsystem_version = major_subsystem_version, | ||
| 795 | .minor_subsystem_version = minor_subsystem_version, | ||
| 796 | .win32_version_value = 0, | ||
| 797 | .size_of_image = 0, | ||
| 798 | .size_of_headers = 0, | ||
| 799 | .checksum = 0, | ||
| 800 | .subsystem = .WINDOWS_CUI, | ||
| 801 | .dll_flags = .{ | ||
| 802 | .HIGH_ENTROPY_VA = true, | ||
| 803 | .DYNAMIC_BASE = true, | ||
| 804 | .TERMINAL_SERVER_AWARE = true, | ||
| 805 | .NX_COMPAT = true, | ||
| 806 | }, | ||
| 807 | .size_of_stack_reserve = default_size_of_stack_reserve, | ||
| 808 | .size_of_stack_commit = default_size_of_stack_commit, | ||
| 809 | .size_of_heap_reserve = default_size_of_heap_reserve, | ||
| 810 | .size_of_heap_commit = default_size_of_heap_commit, | ||
| 811 | .loader_flags = 0, | ||
| 812 | .number_of_rva_and_sizes = DataDirectory.len, | ||
| 813 | }; | ||
| 814 | if (target_endian != native_endian) | ||
| 815 | std.mem.byteSwapAllFields(std.coff.OptionalHeader.PE32, optional_header); | ||
| 816 | }, | ||
| 817 | .@"PE32+" => |optional_header| { | ||
| 818 | optional_header.* = .{ | ||
| 819 | .standard = .{ | ||
| 820 | .magic = .@"PE32+", | ||
| 821 | .major_linker_version = 0, | ||
| 822 | .minor_linker_version = 0, | ||
| 823 | .size_of_code = 0, | ||
| 824 | .size_of_initialized_data = 0, | ||
| 825 | .size_of_uninitialized_data = 0, | ||
| 826 | .address_of_entry_point = 0, | ||
| 827 | .base_of_code = 0, | ||
| 828 | }, | ||
| 829 | .image_base = switch (coff.base.comp.config.output_mode) { | ||
| 830 | .Exe => 0x140000000, | ||
| 831 | .Lib => switch (coff.base.comp.config.link_mode) { | ||
| 832 | .static => 0, | ||
| 833 | .dynamic => 0x180000000, | ||
| 834 | }, | ||
| 835 | .Obj => 0, | ||
| 836 | }, | ||
| 837 | .section_alignment = @intCast(section_align.toByteUnits()), | ||
| 838 | .file_alignment = @intCast(file_align.toByteUnits()), | ||
| 839 | .major_operating_system_version = 6, | ||
| 840 | .minor_operating_system_version = 0, | ||
| 841 | .major_image_version = 0, | ||
| 842 | .minor_image_version = 0, | ||
| 843 | .major_subsystem_version = major_subsystem_version, | ||
| 844 | .minor_subsystem_version = minor_subsystem_version, | ||
| 845 | .win32_version_value = 0, | ||
| 846 | .size_of_image = 0, | ||
| 847 | .size_of_headers = 0, | ||
| 848 | .checksum = 0, | ||
| 849 | .subsystem = .WINDOWS_CUI, | ||
| 850 | .dll_flags = .{ | ||
| 851 | .HIGH_ENTROPY_VA = true, | ||
| 852 | .DYNAMIC_BASE = true, | ||
| 853 | .TERMINAL_SERVER_AWARE = true, | ||
| 854 | .NX_COMPAT = true, | ||
| 855 | }, | ||
| 856 | .size_of_stack_reserve = default_size_of_stack_reserve, | ||
| 857 | .size_of_stack_commit = default_size_of_stack_commit, | ||
| 858 | .size_of_heap_reserve = default_size_of_heap_reserve, | ||
| 859 | .size_of_heap_commit = default_size_of_heap_commit, | ||
| 860 | .loader_flags = 0, | ||
| 861 | .number_of_rva_and_sizes = DataDirectory.len, | ||
| 862 | }; | ||
| 863 | if (target_endian != native_endian) | ||
| 864 | std.mem.byteSwapAllFields(std.coff.OptionalHeader.@"PE32+", optional_header); | ||
| 865 | }, | ||
| 866 | }; | ||
| 867 | |||
| 868 | const data_directories_ni = Node.known.data_directories; | ||
| 869 | assert(data_directories_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ | ||
| 870 | .size = data_directories_size, | ||
| 871 | .alignment = .@"4", | ||
| 872 | .fixed = true, | ||
| 873 | })); | ||
| 874 | coff.nodes.appendAssumeCapacity(.data_directories); | ||
| 875 | { | ||
| 876 | const data_directories = coff.dataDirectorySlice(); | ||
| 877 | @memset(data_directories, .{ .virtual_address = 0, .size = 0 }); | ||
| 878 | if (target_endian != native_endian) | ||
| 879 | std.mem.byteSwapAllFields([DataDirectory.len]std.coff.ImageDataDirectory, data_directories); | ||
| 880 | } | ||
| 881 | |||
| 882 | const section_table_ni = Node.known.section_table; | ||
| 883 | assert(section_table_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ | ||
| 884 | .alignment = .@"4", | ||
| 885 | .fixed = true, | ||
| 886 | })); | ||
| 887 | coff.nodes.appendAssumeCapacity(.section_table); | ||
| 888 | |||
| 889 | assert(coff.nodes.len == Node.known_count); | ||
| 890 | |||
| 891 | try coff.symbol_table.ensureTotalCapacity(gpa, Symbol.Index.known_count); | ||
| 892 | coff.symbol_table.addOneAssumeCapacity().* = .{ | ||
| 893 | .ni = .none, | ||
| 894 | .rva = 0, | ||
| 895 | .size = 0, | ||
| 896 | .loc_relocs = .none, | ||
| 897 | .target_relocs = .none, | ||
| 898 | .section_number = .UNDEFINED, | ||
| 899 | }; | ||
| 900 | assert(try coff.addSection(".data", .{ | ||
| 901 | .CNT_INITIALIZED_DATA = true, | ||
| 902 | .MEM_READ = true, | ||
| 903 | .MEM_WRITE = true, | ||
| 904 | }) == .data); | ||
| 905 | assert(try coff.addSection(".idata", .{ | ||
| 906 | .CNT_INITIALIZED_DATA = true, | ||
| 907 | .MEM_READ = true, | ||
| 908 | }) == .idata); | ||
| 909 | assert(try coff.addSection(".rdata", .{ | ||
| 910 | .CNT_INITIALIZED_DATA = true, | ||
| 911 | .MEM_READ = true, | ||
| 912 | }) == .rdata); | ||
| 913 | assert(try coff.addSection(".text", .{ | ||
| 914 | .CNT_CODE = true, | ||
| 915 | .MEM_EXECUTE = true, | ||
| 916 | .MEM_READ = true, | ||
| 917 | }) == .text); | ||
| 918 | coff.import_table.ni = try coff.mf.addLastChildNode( | ||
| 919 | gpa, | ||
| 920 | Symbol.Index.idata.node(coff), | ||
| 921 | .{ .alignment = .@"4" }, | ||
| 922 | ); | ||
| 923 | coff.nodes.appendAssumeCapacity(.import_directory_table); | ||
| 924 | assert(coff.symbol_table.items.len == Symbol.Index.known_count); | ||
| 925 | } | ||
| 926 | |||
| 927 | fn getNode(coff: *const Coff, ni: MappedFile.Node.Index) Node { | ||
| 928 | return coff.nodes.get(@intFromEnum(ni)); | ||
| 929 | } | ||
| 930 | fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 { | ||
| 931 | const parent_rva = parent_rva: { | ||
| 932 | const parent_si = switch (coff.getNode(ni.parent(&coff.mf))) { | ||
| 933 | .file, | ||
| 934 | .header, | ||
| 935 | .signature, | ||
| 936 | .coff_header, | ||
| 937 | .optional_header, | ||
| 938 | .data_directories, | ||
| 939 | .section_table, | ||
| 940 | => unreachable, | ||
| 941 | .section => |si| si, | ||
| 942 | .import_directory_table => unreachable, | ||
| 943 | .import_lookup_table => |import_index| break :parent_rva coff.targetLoad( | ||
| 944 | &coff.importDirectoryEntryPtr(import_index).import_lookup_table_rva, | ||
| 945 | ), | ||
| 946 | .import_address_table => |import_index| break :parent_rva coff.targetLoad( | ||
| 947 | &coff.importDirectoryEntryPtr(import_index).import_address_table_rva, | ||
| 948 | ), | ||
| 949 | .import_hint_name_table => |import_index| break :parent_rva coff.targetLoad( | ||
| 950 | &coff.importDirectoryEntryPtr(import_index).name_rva, | ||
| 951 | ), | ||
| 952 | inline .global, .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(coff), | ||
| 953 | }; | ||
| 954 | break :parent_rva parent_si.get(coff).rva; | ||
| 955 | }; | ||
| 956 | const offset, _ = ni.location(&coff.mf).resolve(&coff.mf); | ||
| 957 | return @intCast(parent_rva + offset); | ||
| 958 | } | ||
| 959 | |||
| 960 | pub inline fn targetEndian(_: *const Coff) std.builtin.Endian { | ||
| 961 | return .little; | ||
| 962 | } | ||
| 963 | fn targetLoad(coff: *const Coff, ptr: anytype) @typeInfo(@TypeOf(ptr)).pointer.child { | ||
| 964 | const Child = @typeInfo(@TypeOf(ptr)).pointer.child; | ||
| 965 | return switch (@typeInfo(Child)) { | ||
| 966 | else => @compileError(@typeName(Child)), | ||
| 967 | .int => std.mem.toNative(Child, ptr.*, coff.targetEndian()), | ||
| 968 | .@"enum" => |@"enum"| @enumFromInt(coff.targetLoad(@as(*@"enum".tag_type, @ptrCast(ptr)))), | ||
| 969 | .@"struct" => |@"struct"| @bitCast( | ||
| 970 | coff.targetLoad(@as(*@"struct".backing_integer.?, @ptrCast(ptr))), | ||
| 971 | ), | ||
| 972 | }; | ||
| 973 | } | ||
| 974 | fn targetStore(coff: *const Coff, ptr: anytype, val: @typeInfo(@TypeOf(ptr)).pointer.child) void { | ||
| 975 | const Child = @typeInfo(@TypeOf(ptr)).pointer.child; | ||
| 976 | return switch (@typeInfo(Child)) { | ||
| 977 | else => @compileError(@typeName(Child)), | ||
| 978 | .int => ptr.* = std.mem.nativeTo(Child, val, coff.targetEndian()), | ||
| 979 | .@"enum" => |@"enum"| coff.targetStore( | ||
| 980 | @as(*@"enum".tag_type, @ptrCast(ptr)), | ||
| 981 | @intFromEnum(val), | ||
| 982 | ), | ||
| 983 | .@"struct" => |@"struct"| coff.targetStore( | ||
| 984 | @as(*@"struct".backing_integer.?, @ptrCast(ptr)), | ||
| 985 | @bitCast(val), | ||
| 986 | ), | ||
| 987 | }; | ||
| 988 | } | ||
| 989 | |||
| 990 | pub fn headerPtr(coff: *Coff) *std.coff.Header { | ||
| 991 | return @ptrCast(@alignCast(Node.known.coff_header.slice(&coff.mf))); | ||
| 992 | } | ||
| 993 | |||
| 994 | pub fn optionalHeaderStandardPtr(coff: *Coff) *std.coff.OptionalHeader { | ||
| 995 | return @ptrCast(@alignCast( | ||
| 996 | Node.known.optional_header.slice(&coff.mf)[0..@sizeOf(std.coff.OptionalHeader)], | ||
| 997 | )); | ||
| 998 | } | ||
| 999 | |||
| 1000 | pub const OptionalHeaderPtr = union(std.coff.OptionalHeader.Magic) { | ||
| 1001 | PE32: *std.coff.OptionalHeader.PE32, | ||
| 1002 | @"PE32+": *std.coff.OptionalHeader.@"PE32+", | ||
| 1003 | }; | ||
| 1004 | pub fn optionalHeaderPtr(coff: *Coff) OptionalHeaderPtr { | ||
| 1005 | const slice = Node.known.optional_header.slice(&coff.mf); | ||
| 1006 | return switch (coff.targetLoad(&coff.optionalHeaderStandardPtr().magic)) { | ||
| 1007 | _ => unreachable, | ||
| 1008 | inline else => |magic| @unionInit( | ||
| 1009 | OptionalHeaderPtr, | ||
| 1010 | @tagName(magic), | ||
| 1011 | @ptrCast(@alignCast(slice)), | ||
| 1012 | ), | ||
| 1013 | }; | ||
| 1014 | } | ||
| 1015 | pub fn optionalHeaderField( | ||
| 1016 | coff: *Coff, | ||
| 1017 | comptime field: std.meta.FieldEnum(std.coff.OptionalHeader.@"PE32+"), | ||
| 1018 | ) @FieldType(std.coff.OptionalHeader.@"PE32+", @tagName(field)) { | ||
| 1019 | return switch (coff.optionalHeaderPtr()) { | ||
| 1020 | inline else => |optional_header| coff.targetLoad(&@field(optional_header, @tagName(field))), | ||
| 1021 | }; | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | pub fn dataDirectorySlice(coff: *Coff) *[DataDirectory.len]std.coff.ImageDataDirectory { | ||
| 1025 | return @ptrCast(@alignCast(Node.known.data_directories.slice(&coff.mf))); | ||
| 1026 | } | ||
| 1027 | pub fn dataDirectoryPtr(coff: *Coff, data_directory: DataDirectory) *std.coff.ImageDataDirectory { | ||
| 1028 | return &coff.dataDirectorySlice()[@intFromEnum(data_directory)]; | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | pub fn sectionTableSlice(coff: *Coff) []std.coff.SectionHeader { | ||
| 1032 | return @ptrCast(@alignCast(Node.known.section_table.slice(&coff.mf))); | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | pub fn importDirectoryTableSlice(coff: *Coff) []std.coff.ImportDirectoryEntry { | ||
| 1036 | return @ptrCast(@alignCast(coff.import_table.ni.slice(&coff.mf))); | ||
| 1037 | } | ||
| 1038 | pub fn importDirectoryEntryPtr( | ||
| 1039 | coff: *Coff, | ||
| 1040 | import_index: ImportTable.Index, | ||
| 1041 | ) *std.coff.ImportDirectoryEntry { | ||
| 1042 | return &coff.importDirectoryTableSlice()[@intFromEnum(import_index)]; | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index { | ||
| 1046 | defer coff.symbol_table.addOneAssumeCapacity().* = .{ | ||
| 1047 | .ni = .none, | ||
| 1048 | .rva = 0, | ||
| 1049 | .size = 0, | ||
| 1050 | .loc_relocs = .none, | ||
| 1051 | .target_relocs = .none, | ||
| 1052 | .section_number = .UNDEFINED, | ||
| 1053 | }; | ||
| 1054 | return @enumFromInt(coff.symbol_table.items.len); | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | fn initSymbolAssumeCapacity(coff: *Coff) !Symbol.Index { | ||
| 1058 | const si = coff.addSymbolAssumeCapacity(); | ||
| 1059 | return si; | ||
| 1060 | } | ||
| 1061 | |||
| 1062 | fn getOrPutString(coff: *Coff, string: []const u8) !String { | ||
| 1063 | const gpa = coff.base.comp.gpa; | ||
| 1064 | try coff.string_bytes.ensureUnusedCapacity(gpa, string.len + 1); | ||
| 1065 | const gop = try coff.strings.getOrPutContextAdapted( | ||
| 1066 | gpa, | ||
| 1067 | string, | ||
| 1068 | std.hash_map.StringIndexAdapter{ .bytes = &coff.string_bytes }, | ||
| 1069 | .{ .bytes = &coff.string_bytes }, | ||
| 1070 | ); | ||
| 1071 | if (!gop.found_existing) { | ||
| 1072 | gop.key_ptr.* = @intCast(coff.string_bytes.items.len); | ||
| 1073 | gop.value_ptr.* = {}; | ||
| 1074 | coff.string_bytes.appendSliceAssumeCapacity(string); | ||
| 1075 | coff.string_bytes.appendAssumeCapacity(0); | ||
| 1076 | } | ||
| 1077 | return @enumFromInt(gop.key_ptr.*); | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | fn getOrPutOptionalString(coff: *Coff, string: ?[]const u8) !String.Optional { | ||
| 1081 | return (try coff.getOrPutString(string orelse return .none)).toOptional(); | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbol.Index { | ||
| 1085 | const gpa = coff.base.comp.gpa; | ||
| 1086 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | ||
| 1087 | const sym_gop = try coff.globals.getOrPut(gpa, .{ | ||
| 1088 | .name = try coff.getOrPutString(name), | ||
| 1089 | .lib_name = try coff.getOrPutOptionalString(lib_name), | ||
| 1090 | }); | ||
| 1091 | if (!sym_gop.found_existing) { | ||
| 1092 | sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity(); | ||
| 1093 | coff.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1); | ||
| 1094 | } | ||
| 1095 | return sym_gop.value_ptr.*; | ||
| 1096 | } | ||
| 1097 | |||
| 1098 | fn navMapIndex(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex { | ||
| 1099 | const gpa = zcu.gpa; | ||
| 1100 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | ||
| 1101 | const sym_gop = try coff.navs.getOrPut(gpa, nav_index); | ||
| 1102 | if (!sym_gop.found_existing) sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity(); | ||
| 1103 | return @enumFromInt(sym_gop.index); | ||
| 1104 | } | ||
| 1105 | pub fn navSymbol(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index { | ||
| 1106 | const ip = &zcu.intern_pool; | ||
| 1107 | const nav = ip.getNav(nav_index); | ||
| 1108 | if (nav.getExtern(ip)) |@"extern"| return coff.globalSymbol( | ||
| 1109 | @"extern".name.toSlice(ip), | ||
| 1110 | @"extern".lib_name.toSlice(ip), | ||
| 1111 | ); | ||
| 1112 | const nmi = try coff.navMapIndex(zcu, nav_index); | ||
| 1113 | return nmi.symbol(coff); | ||
| 1114 | } | ||
| 1115 | |||
| 1116 | fn uavMapIndex(coff: *Coff, uav_val: InternPool.Index) !Node.UavMapIndex { | ||
| 1117 | const gpa = coff.base.comp.gpa; | ||
| 1118 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | ||
| 1119 | const sym_gop = try coff.uavs.getOrPut(gpa, uav_val); | ||
| 1120 | if (!sym_gop.found_existing) sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity(); | ||
| 1121 | return @enumFromInt(sym_gop.index); | ||
| 1122 | } | ||
| 1123 | pub fn uavSymbol(coff: *Coff, uav_val: InternPool.Index) !Symbol.Index { | ||
| 1124 | const umi = try coff.uavMapIndex(uav_val); | ||
| 1125 | return umi.symbol(coff); | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | pub fn lazySymbol(coff: *Coff, lazy: link.File.LazySymbol) !Symbol.Index { | ||
| 1129 | const gpa = coff.base.comp.gpa; | ||
| 1130 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | ||
| 1131 | const sym_gop = try coff.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty); | ||
| 1132 | if (!sym_gop.found_existing) { | ||
| 1133 | sym_gop.value_ptr.* = try coff.initSymbolAssumeCapacity(); | ||
| 1134 | coff.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1); | ||
| 1135 | } | ||
| 1136 | return sym_gop.value_ptr.*; | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | pub fn getNavVAddr( | ||
| 1140 | coff: *Coff, | ||
| 1141 | pt: Zcu.PerThread, | ||
| 1142 | nav: InternPool.Nav.Index, | ||
| 1143 | reloc_info: link.File.RelocInfo, | ||
| 1144 | ) !u64 { | ||
| 1145 | return coff.getVAddr(reloc_info, try coff.navSymbol(pt.zcu, nav)); | ||
| 1146 | } | ||
| 1147 | |||
| 1148 | pub fn getUavVAddr( | ||
| 1149 | coff: *Coff, | ||
| 1150 | uav: InternPool.Index, | ||
| 1151 | reloc_info: link.File.RelocInfo, | ||
| 1152 | ) !u64 { | ||
| 1153 | return coff.getVAddr(reloc_info, try coff.uavSymbol(uav)); | ||
| 1154 | } | ||
| 1155 | |||
| 1156 | pub fn getVAddr(coff: *Coff, reloc_info: link.File.RelocInfo, target_si: Symbol.Index) !u64 { | ||
| 1157 | try coff.addReloc( | ||
| 1158 | @enumFromInt(reloc_info.parent.atom_index), | ||
| 1159 | reloc_info.offset, | ||
| 1160 | target_si, | ||
| 1161 | reloc_info.addend, | ||
| 1162 | switch (coff.targetLoad(&coff.headerPtr().machine)) { | ||
| 1163 | else => unreachable, | ||
| 1164 | .AMD64 => .{ .AMD64 = .ADDR64 }, | ||
| 1165 | .I386 => .{ .I386 = .DIR32 }, | ||
| 1166 | }, | ||
| 1167 | ); | ||
| 1168 | return coff.optionalHeaderField(.image_base) + target_si.get(coff).rva; | ||
| 1169 | } | ||
| 1170 | |||
| 1171 | fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags) !Symbol.Index { | ||
| 1172 | const gpa = coff.base.comp.gpa; | ||
| 1173 | try coff.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 1174 | try coff.section_table.ensureUnusedCapacity(gpa, 1); | ||
| 1175 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | ||
| 1176 | |||
| 1177 | const coff_header = coff.headerPtr(); | ||
| 1178 | const section_index = coff.targetLoad(&coff_header.number_of_sections); | ||
| 1179 | const section_table_len = section_index + 1; | ||
| 1180 | coff.targetStore(&coff_header.number_of_sections, section_table_len); | ||
| 1181 | try Node.known.section_table.resize( | ||
| 1182 | &coff.mf, | ||
| 1183 | gpa, | ||
| 1184 | @sizeOf(std.coff.SectionHeader) * section_table_len, | ||
| 1185 | ); | ||
| 1186 | const ni = try coff.mf.addLastChildNode(gpa, .root, .{ | ||
| 1187 | .alignment = coff.mf.flags.block_size, | ||
| 1188 | .moved = true, | ||
| 1189 | .bubbles_moved = false, | ||
| 1190 | }); | ||
| 1191 | const si = coff.addSymbolAssumeCapacity(); | ||
| 1192 | coff.section_table.appendAssumeCapacity(si); | ||
| 1193 | coff.nodes.appendAssumeCapacity(.{ .section = si }); | ||
| 1194 | const section_table = coff.sectionTableSlice(); | ||
| 1195 | const virtual_size = coff.optionalHeaderField(.section_alignment); | ||
| 1196 | const rva: u32 = switch (section_index) { | ||
| 1197 | 0 => @intCast(Node.known.header.location(&coff.mf).resolve(&coff.mf)[1]), | ||
| 1198 | else => coff.section_table.items[section_index - 1].get(coff).rva + | ||
| 1199 | coff.targetLoad(&section_table[section_index - 1].virtual_size), | ||
| 1200 | }; | ||
| 1201 | { | ||
| 1202 | const sym = si.get(coff); | ||
| 1203 | sym.ni = ni; | ||
| 1204 | sym.rva = rva; | ||
| 1205 | sym.section_number = @enumFromInt(section_table_len); | ||
| 1206 | } | ||
| 1207 | const section = &section_table[section_index]; | ||
| 1208 | section.* = .{ | ||
| 1209 | .name = undefined, | ||
| 1210 | .virtual_size = virtual_size, | ||
| 1211 | .virtual_address = rva, | ||
| 1212 | .size_of_raw_data = 0, | ||
| 1213 | .pointer_to_raw_data = 0, | ||
| 1214 | .pointer_to_relocations = 0, | ||
| 1215 | .pointer_to_linenumbers = 0, | ||
| 1216 | .number_of_relocations = 0, | ||
| 1217 | .number_of_linenumbers = 0, | ||
| 1218 | .flags = flags, | ||
| 1219 | }; | ||
| 1220 | @memcpy(section.name[0..name.len], name); | ||
| 1221 | @memset(section.name[name.len..], 0); | ||
| 1222 | if (coff.targetEndian() != native_endian) | ||
| 1223 | std.mem.byteSwapAllFields(std.coff.SectionHeader, section); | ||
| 1224 | switch (coff.optionalHeaderPtr()) { | ||
| 1225 | inline else => |optional_header| coff.targetStore( | ||
| 1226 | &optional_header.size_of_image, | ||
| 1227 | @intCast(rva + virtual_size), | ||
| 1228 | ), | ||
| 1229 | } | ||
| 1230 | return si; | ||
| 1231 | } | ||
| 1232 | |||
| 1233 | pub fn addReloc( | ||
| 1234 | coff: *Coff, | ||
| 1235 | loc_si: Symbol.Index, | ||
| 1236 | offset: u64, | ||
| 1237 | target_si: Symbol.Index, | ||
| 1238 | addend: i64, | ||
| 1239 | @"type": Reloc.Type, | ||
| 1240 | ) !void { | ||
| 1241 | const gpa = coff.base.comp.gpa; | ||
| 1242 | const target = target_si.get(coff); | ||
| 1243 | const ri: Reloc.Index = @enumFromInt(coff.relocs.items.len); | ||
| 1244 | (try coff.relocs.addOne(gpa)).* = .{ | ||
| 1245 | .type = @"type", | ||
| 1246 | .prev = .none, | ||
| 1247 | .next = target.target_relocs, | ||
| 1248 | .loc = loc_si, | ||
| 1249 | .target = target_si, | ||
| 1250 | .unused = 0, | ||
| 1251 | .offset = offset, | ||
| 1252 | .addend = addend, | ||
| 1253 | }; | ||
| 1254 | switch (target.target_relocs) { | ||
| 1255 | .none => {}, | ||
| 1256 | else => |target_ri| target_ri.get(coff).prev = ri, | ||
| 1257 | } | ||
| 1258 | target.target_relocs = ri; | ||
| 1259 | } | ||
| 1260 | |||
| 1261 | pub fn prelink(coff: *Coff, prog_node: std.Progress.Node) void { | ||
| 1262 | _ = coff; | ||
| 1263 | _ = prog_node; | ||
| 1264 | } | ||
| 1265 | |||
| 1266 | pub fn updateNav(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { | ||
| 1267 | coff.updateNavInner(pt, nav_index) catch |err| switch (err) { | ||
| 1268 | error.OutOfMemory, | ||
| 1269 | error.Overflow, | ||
| 1270 | error.RelocationNotByteAligned, | ||
| 1271 | => |e| return e, | ||
| 1272 | else => |e| return coff.base.cgFail(nav_index, "linker failed to update variable: {t}", .{e}), | ||
| 1273 | }; | ||
| 1274 | } | ||
| 1275 | fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { | ||
| 1276 | const zcu = pt.zcu; | ||
| 1277 | const gpa = zcu.gpa; | ||
| 1278 | const ip = &zcu.intern_pool; | ||
| 1279 | |||
| 1280 | const nav = ip.getNav(nav_index); | ||
| 1281 | const nav_val = nav.status.fully_resolved.val; | ||
| 1282 | const nav_init, const is_threadlocal = switch (ip.indexToKey(nav_val)) { | ||
| 1283 | else => .{ nav_val, false }, | ||
| 1284 | .variable => |variable| .{ variable.init, variable.is_threadlocal }, | ||
| 1285 | .@"extern" => return, | ||
| 1286 | .func => .{ .none, false }, | ||
| 1287 | }; | ||
| 1288 | if (nav_init == .none or !Type.fromInterned(ip.typeOf(nav_init)).hasRuntimeBits(zcu)) return; | ||
| 1289 | |||
| 1290 | const nmi = try coff.navMapIndex(zcu, nav_index); | ||
| 1291 | const si = nmi.symbol(coff); | ||
| 1292 | const ni = ni: { | ||
| 1293 | const sym = si.get(coff); | ||
| 1294 | switch (sym.ni) { | ||
| 1295 | .none => { | ||
| 1296 | try coff.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 1297 | _ = is_threadlocal; | ||
| 1298 | const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.data.node(coff), .{ | ||
| 1299 | .alignment = pt.navAlignment(nav_index).toStdMem(), | ||
| 1300 | .moved = true, | ||
| 1301 | }); | ||
| 1302 | coff.nodes.appendAssumeCapacity(.{ .nav = nmi }); | ||
| 1303 | sym.ni = ni; | ||
| 1304 | sym.section_number = Symbol.Index.data.get(coff).section_number; | ||
| 1305 | }, | ||
| 1306 | else => si.deleteLocationRelocs(coff), | ||
| 1307 | } | ||
| 1308 | assert(sym.loc_relocs == .none); | ||
| 1309 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | ||
| 1310 | break :ni sym.ni; | ||
| 1311 | }; | ||
| 1312 | |||
| 1313 | var nw: MappedFile.Node.Writer = undefined; | ||
| 1314 | ni.writer(&coff.mf, gpa, &nw); | ||
| 1315 | defer nw.deinit(); | ||
| 1316 | codegen.generateSymbol( | ||
| 1317 | &coff.base, | ||
| 1318 | pt, | ||
| 1319 | zcu.navSrcLoc(nav_index), | ||
| 1320 | .fromInterned(nav_init), | ||
| 1321 | &nw.interface, | ||
| 1322 | .{ .atom_index = @intFromEnum(si) }, | ||
| 1323 | ) catch |err| switch (err) { | ||
| 1324 | error.WriteFailed => return error.OutOfMemory, | ||
| 1325 | else => |e| return e, | ||
| 1326 | }; | ||
| 1327 | si.get(coff).size = @intCast(nw.interface.end); | ||
| 1328 | si.applyLocationRelocs(coff); | ||
| 1329 | } | ||
| 1330 | |||
| 1331 | pub fn lowerUav( | ||
| 1332 | coff: *Coff, | ||
| 1333 | pt: Zcu.PerThread, | ||
| 1334 | uav_val: InternPool.Index, | ||
| 1335 | uav_align: InternPool.Alignment, | ||
| 1336 | src_loc: Zcu.LazySrcLoc, | ||
| 1337 | ) !codegen.SymbolResult { | ||
| 1338 | const zcu = pt.zcu; | ||
| 1339 | const gpa = zcu.gpa; | ||
| 1340 | |||
| 1341 | try coff.pending_uavs.ensureUnusedCapacity(gpa, 1); | ||
| 1342 | const umi = try coff.uavMapIndex(uav_val); | ||
| 1343 | const si = umi.symbol(coff); | ||
| 1344 | if (switch (si.get(coff).ni) { | ||
| 1345 | .none => true, | ||
| 1346 | else => |ni| uav_align.toStdMem().order(ni.alignment(&coff.mf)).compare(.gt), | ||
| 1347 | }) { | ||
| 1348 | const gop = coff.pending_uavs.getOrPutAssumeCapacity(umi); | ||
| 1349 | if (gop.found_existing) { | ||
| 1350 | gop.value_ptr.alignment = gop.value_ptr.alignment.max(uav_align); | ||
| 1351 | } else { | ||
| 1352 | gop.value_ptr.* = .{ | ||
| 1353 | .alignment = uav_align, | ||
| 1354 | .src_loc = src_loc, | ||
| 1355 | }; | ||
| 1356 | coff.base.comp.link_const_prog_node.increaseEstimatedTotalItems(1); | ||
| 1357 | } | ||
| 1358 | } | ||
| 1359 | return .{ .sym_index = @intFromEnum(si) }; | ||
| 1360 | } | ||
| 1361 | |||
| 1362 | pub fn updateFunc( | ||
| 1363 | coff: *Coff, | ||
| 1364 | pt: Zcu.PerThread, | ||
| 1365 | func_index: InternPool.Index, | ||
| 1366 | mir: *const codegen.AnyMir, | ||
| 1367 | ) !void { | ||
| 1368 | coff.updateFuncInner(pt, func_index, mir) catch |err| switch (err) { | ||
| 1369 | error.OutOfMemory, | ||
| 1370 | error.Overflow, | ||
| 1371 | error.RelocationNotByteAligned, | ||
| 1372 | error.CodegenFail, | ||
| 1373 | => |e| return e, | ||
| 1374 | else => |e| return coff.base.cgFail( | ||
| 1375 | pt.zcu.funcInfo(func_index).owner_nav, | ||
| 1376 | "linker failed to update function: {s}", | ||
| 1377 | .{@errorName(e)}, | ||
| 1378 | ), | ||
| 1379 | }; | ||
| 1380 | } | ||
| 1381 | fn updateFuncInner( | ||
| 1382 | coff: *Coff, | ||
| 1383 | pt: Zcu.PerThread, | ||
| 1384 | func_index: InternPool.Index, | ||
| 1385 | mir: *const codegen.AnyMir, | ||
| 1386 | ) !void { | ||
| 1387 | const zcu = pt.zcu; | ||
| 1388 | const gpa = zcu.gpa; | ||
| 1389 | const ip = &zcu.intern_pool; | ||
| 1390 | const func = zcu.funcInfo(func_index); | ||
| 1391 | const nav = ip.getNav(func.owner_nav); | ||
| 1392 | |||
| 1393 | const nmi = try coff.navMapIndex(zcu, func.owner_nav); | ||
| 1394 | const si = nmi.symbol(coff); | ||
| 1395 | log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), si }); | ||
| 1396 | const ni = ni: { | ||
| 1397 | const sym = si.get(coff); | ||
| 1398 | switch (sym.ni) { | ||
| 1399 | .none => { | ||
| 1400 | try coff.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 1401 | const mod = zcu.navFileScope(func.owner_nav).mod.?; | ||
| 1402 | const target = &mod.resolved_target.result; | ||
| 1403 | const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.text.node(coff), .{ | ||
| 1404 | .alignment = switch (nav.status.fully_resolved.alignment) { | ||
| 1405 | .none => switch (mod.optimize_mode) { | ||
| 1406 | .Debug, | ||
| 1407 | .ReleaseSafe, | ||
| 1408 | .ReleaseFast, | ||
| 1409 | => target_util.defaultFunctionAlignment(target), | ||
| 1410 | .ReleaseSmall => target_util.minFunctionAlignment(target), | ||
| 1411 | }, | ||
| 1412 | else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), | ||
| 1413 | }.toStdMem(), | ||
| 1414 | .moved = true, | ||
| 1415 | }); | ||
| 1416 | coff.nodes.appendAssumeCapacity(.{ .nav = nmi }); | ||
| 1417 | sym.ni = ni; | ||
| 1418 | sym.section_number = Symbol.Index.text.get(coff).section_number; | ||
| 1419 | }, | ||
| 1420 | else => si.deleteLocationRelocs(coff), | ||
| 1421 | } | ||
| 1422 | assert(sym.loc_relocs == .none); | ||
| 1423 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | ||
| 1424 | break :ni sym.ni; | ||
| 1425 | }; | ||
| 1426 | |||
| 1427 | var nw: MappedFile.Node.Writer = undefined; | ||
| 1428 | ni.writer(&coff.mf, gpa, &nw); | ||
| 1429 | defer nw.deinit(); | ||
| 1430 | codegen.emitFunction( | ||
| 1431 | &coff.base, | ||
| 1432 | pt, | ||
| 1433 | zcu.navSrcLoc(func.owner_nav), | ||
| 1434 | func_index, | ||
| 1435 | @intFromEnum(si), | ||
| 1436 | mir, | ||
| 1437 | &nw.interface, | ||
| 1438 | .none, | ||
| 1439 | ) catch |err| switch (err) { | ||
| 1440 | error.WriteFailed => return nw.err.?, | ||
| 1441 | else => |e| return e, | ||
| 1442 | }; | ||
| 1443 | si.get(coff).size = @intCast(nw.interface.end); | ||
| 1444 | si.applyLocationRelocs(coff); | ||
| 1445 | } | ||
| 1446 | |||
| 1447 | pub fn updateErrorData(coff: *Coff, pt: Zcu.PerThread) !void { | ||
| 1448 | coff.flushLazy(pt, .{ | ||
| 1449 | .kind = .const_data, | ||
| 1450 | .index = @intCast(coff.lazy.getPtr(.const_data).map.getIndex(.anyerror_type) orelse return), | ||
| 1451 | }) catch |err| switch (err) { | ||
| 1452 | error.OutOfMemory => return error.OutOfMemory, | ||
| 1453 | error.CodegenFail => return error.LinkFailure, | ||
| 1454 | else => |e| return coff.base.comp.link_diags.fail("updateErrorData failed {t}", .{e}), | ||
| 1455 | }; | ||
| 1456 | } | ||
| 1457 | |||
| 1458 | pub fn flush( | ||
| 1459 | coff: *Coff, | ||
| 1460 | arena: std.mem.Allocator, | ||
| 1461 | tid: Zcu.PerThread.Id, | ||
| 1462 | prog_node: std.Progress.Node, | ||
| 1463 | ) !void { | ||
| 1464 | _ = arena; | ||
| 1465 | _ = prog_node; | ||
| 1466 | while (try coff.idle(tid)) {} | ||
| 1467 | |||
| 1468 | // hack for stage2_x86_64 + coff | ||
| 1469 | const comp = coff.base.comp; | ||
| 1470 | if (comp.compiler_rt_dyn_lib) |crt_file| { | ||
| 1471 | const gpa = comp.gpa; | ||
| 1472 | const compiler_rt_sub_path = try std.fs.path.join(gpa, &.{ | ||
| 1473 | std.fs.path.dirname(coff.base.emit.sub_path) orelse "", | ||
| 1474 | std.fs.path.basename(crt_file.full_object_path.sub_path), | ||
| 1475 | }); | ||
| 1476 | defer gpa.free(compiler_rt_sub_path); | ||
| 1477 | crt_file.full_object_path.root_dir.handle.copyFile( | ||
| 1478 | crt_file.full_object_path.sub_path, | ||
| 1479 | coff.base.emit.root_dir.handle, | ||
| 1480 | compiler_rt_sub_path, | ||
| 1481 | .{}, | ||
| 1482 | ) catch |err| switch (err) { | ||
| 1483 | else => |e| return comp.link_diags.fail("Copy '{s}' failed: {s}", .{ | ||
| 1484 | compiler_rt_sub_path, | ||
| 1485 | @errorName(e), | ||
| 1486 | }), | ||
| 1487 | }; | ||
| 1488 | } | ||
| 1489 | } | ||
| 1490 | |||
| 1491 | pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { | ||
| 1492 | const comp = coff.base.comp; | ||
| 1493 | task: { | ||
| 1494 | while (coff.pending_uavs.pop()) |pending_uav| { | ||
| 1495 | const sub_prog_node = coff.idleProgNode( | ||
| 1496 | tid, | ||
| 1497 | comp.link_const_prog_node, | ||
| 1498 | .{ .uav = pending_uav.key }, | ||
| 1499 | ); | ||
| 1500 | defer sub_prog_node.end(); | ||
| 1501 | coff.flushUav( | ||
| 1502 | .{ .zcu = coff.base.comp.zcu.?, .tid = tid }, | ||
| 1503 | pending_uav.key, | ||
| 1504 | pending_uav.value.alignment, | ||
| 1505 | pending_uav.value.src_loc, | ||
| 1506 | ) catch |err| switch (err) { | ||
| 1507 | error.OutOfMemory => return error.OutOfMemory, | ||
| 1508 | else => |e| return coff.base.comp.link_diags.fail( | ||
| 1509 | "linker failed to lower constant: {t}", | ||
| 1510 | .{e}, | ||
| 1511 | ), | ||
| 1512 | }; | ||
| 1513 | break :task; | ||
| 1514 | } | ||
| 1515 | if (coff.global_pending_index < coff.globals.count()) { | ||
| 1516 | const pt: Zcu.PerThread = .{ .zcu = coff.base.comp.zcu.?, .tid = tid }; | ||
| 1517 | const gmi: Node.GlobalMapIndex = @enumFromInt(coff.global_pending_index); | ||
| 1518 | coff.global_pending_index += 1; | ||
| 1519 | const sub_prog_node = comp.link_synth_prog_node.start( | ||
| 1520 | gmi.globalName(coff).name.toSlice(coff), | ||
| 1521 | 0, | ||
| 1522 | ); | ||
| 1523 | defer sub_prog_node.end(); | ||
| 1524 | coff.flushGlobal(pt, gmi) catch |err| switch (err) { | ||
| 1525 | error.OutOfMemory => return error.OutOfMemory, | ||
| 1526 | else => |e| return coff.base.comp.link_diags.fail( | ||
| 1527 | "linker failed to lower constant: {t}", | ||
| 1528 | .{e}, | ||
| 1529 | ), | ||
| 1530 | }; | ||
| 1531 | break :task; | ||
| 1532 | } | ||
| 1533 | var lazy_it = coff.lazy.iterator(); | ||
| 1534 | while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) { | ||
| 1535 | const pt: Zcu.PerThread = .{ .zcu = coff.base.comp.zcu.?, .tid = tid }; | ||
| 1536 | const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index }; | ||
| 1537 | lazy.value.pending_index += 1; | ||
| 1538 | const kind = switch (lmr.kind) { | ||
| 1539 | .code => "code", | ||
| 1540 | .const_data => "data", | ||
| 1541 | }; | ||
| 1542 | var name: [std.Progress.Node.max_name_len]u8 = undefined; | ||
| 1543 | const sub_prog_node = comp.link_synth_prog_node.start( | ||
| 1544 | std.fmt.bufPrint(&name, "lazy {s} for {f}", .{ | ||
| 1545 | kind, | ||
| 1546 | Type.fromInterned(lmr.lazySymbol(coff).ty).fmt(pt), | ||
| 1547 | }) catch &name, | ||
| 1548 | 0, | ||
| 1549 | ); | ||
| 1550 | defer sub_prog_node.end(); | ||
| 1551 | coff.flushLazy(pt, lmr) catch |err| switch (err) { | ||
| 1552 | error.OutOfMemory => return error.OutOfMemory, | ||
| 1553 | else => |e| return coff.base.comp.link_diags.fail( | ||
| 1554 | "linker failed to lower lazy {s}: {t}", | ||
| 1555 | .{ kind, e }, | ||
| 1556 | ), | ||
| 1557 | }; | ||
| 1558 | break :task; | ||
| 1559 | }; | ||
| 1560 | while (coff.mf.updates.pop()) |ni| { | ||
| 1561 | const clean_moved = ni.cleanMoved(&coff.mf); | ||
| 1562 | const clean_resized = ni.cleanResized(&coff.mf); | ||
| 1563 | if (clean_moved or clean_resized) { | ||
| 1564 | const sub_prog_node = coff.idleProgNode(tid, coff.mf.update_prog_node, coff.getNode(ni)); | ||
| 1565 | defer sub_prog_node.end(); | ||
| 1566 | if (clean_moved) try coff.flushMoved(ni); | ||
| 1567 | if (clean_resized) try coff.flushResized(ni); | ||
| 1568 | break :task; | ||
| 1569 | } else coff.mf.update_prog_node.completeOne(); | ||
| 1570 | } | ||
| 1571 | } | ||
| 1572 | if (coff.pending_uavs.count() > 0) return true; | ||
| 1573 | for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; | ||
| 1574 | if (coff.mf.updates.items.len > 0) return true; | ||
| 1575 | return false; | ||
| 1576 | } | ||
| 1577 | |||
| 1578 | fn idleProgNode( | ||
| 1579 | coff: *Coff, | ||
| 1580 | tid: Zcu.PerThread.Id, | ||
| 1581 | prog_node: std.Progress.Node, | ||
| 1582 | node: Node, | ||
| 1583 | ) std.Progress.Node { | ||
| 1584 | var name: [std.Progress.Node.max_name_len]u8 = undefined; | ||
| 1585 | return prog_node.start(name: switch (node) { | ||
| 1586 | else => |tag| @tagName(tag), | ||
| 1587 | .section => |si| std.mem.sliceTo(&si.get(coff).section_number.header(coff).name, 0), | ||
| 1588 | .nav => |nmi| { | ||
| 1589 | const ip = &coff.base.comp.zcu.?.intern_pool; | ||
| 1590 | break :name ip.getNav(nmi.navIndex(coff)).fqn.toSlice(ip); | ||
| 1591 | }, | ||
| 1592 | .uav => |umi| std.fmt.bufPrint(&name, "{f}", .{ | ||
| 1593 | Value.fromInterned(umi.uavValue(coff)).fmtValue(.{ | ||
| 1594 | .zcu = coff.base.comp.zcu.?, | ||
| 1595 | .tid = tid, | ||
| 1596 | }), | ||
| 1597 | }) catch &name, | ||
| 1598 | }, 0); | ||
| 1599 | } | ||
| 1600 | |||
| 1601 | fn flushUav( | ||
| 1602 | coff: *Coff, | ||
| 1603 | pt: Zcu.PerThread, | ||
| 1604 | umi: Node.UavMapIndex, | ||
| 1605 | uav_align: InternPool.Alignment, | ||
| 1606 | src_loc: Zcu.LazySrcLoc, | ||
| 1607 | ) !void { | ||
| 1608 | const zcu = pt.zcu; | ||
| 1609 | const gpa = zcu.gpa; | ||
| 1610 | |||
| 1611 | const uav_val = umi.uavValue(coff); | ||
| 1612 | const si = umi.symbol(coff); | ||
| 1613 | const ni = ni: { | ||
| 1614 | const sym = si.get(coff); | ||
| 1615 | switch (sym.ni) { | ||
| 1616 | .none => { | ||
| 1617 | try coff.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 1618 | const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.data.node(coff), .{ | ||
| 1619 | .alignment = uav_align.toStdMem(), | ||
| 1620 | .moved = true, | ||
| 1621 | }); | ||
| 1622 | coff.nodes.appendAssumeCapacity(.{ .uav = umi }); | ||
| 1623 | sym.ni = ni; | ||
| 1624 | sym.section_number = Symbol.Index.data.get(coff).section_number; | ||
| 1625 | }, | ||
| 1626 | else => { | ||
| 1627 | if (sym.ni.alignment(&coff.mf).order(uav_align.toStdMem()).compare(.gte)) return; | ||
| 1628 | si.deleteLocationRelocs(coff); | ||
| 1629 | }, | ||
| 1630 | } | ||
| 1631 | assert(sym.loc_relocs == .none); | ||
| 1632 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | ||
| 1633 | break :ni sym.ni; | ||
| 1634 | }; | ||
| 1635 | |||
| 1636 | var nw: MappedFile.Node.Writer = undefined; | ||
| 1637 | ni.writer(&coff.mf, gpa, &nw); | ||
| 1638 | defer nw.deinit(); | ||
| 1639 | codegen.generateSymbol( | ||
| 1640 | &coff.base, | ||
| 1641 | pt, | ||
| 1642 | src_loc, | ||
| 1643 | .fromInterned(uav_val), | ||
| 1644 | &nw.interface, | ||
| 1645 | .{ .atom_index = @intFromEnum(si) }, | ||
| 1646 | ) catch |err| switch (err) { | ||
| 1647 | error.WriteFailed => return error.OutOfMemory, | ||
| 1648 | else => |e| return e, | ||
| 1649 | }; | ||
| 1650 | si.get(coff).size = @intCast(nw.interface.end); | ||
| 1651 | si.applyLocationRelocs(coff); | ||
| 1652 | } | ||
| 1653 | |||
| 1654 | fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void { | ||
| 1655 | const zcu = pt.zcu; | ||
| 1656 | const comp = zcu.comp; | ||
| 1657 | const gpa = zcu.gpa; | ||
| 1658 | const gn = gmi.globalName(coff); | ||
| 1659 | if (gn.lib_name.toSlice(coff)) |lib_name| { | ||
| 1660 | const name = gn.name.toSlice(coff); | ||
| 1661 | try coff.nodes.ensureUnusedCapacity(gpa, 4); | ||
| 1662 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | ||
| 1663 | |||
| 1664 | const target_endian = coff.targetEndian(); | ||
| 1665 | const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic); | ||
| 1666 | const addr_size: u64, const addr_align: std.mem.Alignment = switch (magic) { | ||
| 1667 | _ => unreachable, | ||
| 1668 | .PE32 => .{ 4, .@"4" }, | ||
| 1669 | .@"PE32+" => .{ 8, .@"8" }, | ||
| 1670 | }; | ||
| 1671 | |||
| 1672 | const gop = try coff.import_table.entries.getOrPutAdapted( | ||
| 1673 | gpa, | ||
| 1674 | lib_name, | ||
| 1675 | ImportTable.Adapter{ .coff = coff }, | ||
| 1676 | ); | ||
| 1677 | const import_hint_name_align: std.mem.Alignment = .@"2"; | ||
| 1678 | if (!gop.found_existing) { | ||
| 1679 | errdefer _ = coff.import_table.entries.pop(); | ||
| 1680 | try coff.import_table.ni.resize( | ||
| 1681 | &coff.mf, | ||
| 1682 | gpa, | ||
| 1683 | @sizeOf(std.coff.ImportDirectoryEntry) * (gop.index + 2), | ||
| 1684 | ); | ||
| 1685 | const import_hint_name_table_len = | ||
| 1686 | import_hint_name_align.forward(lib_name.len + ".dll".len + 1); | ||
| 1687 | const idata_section_ni = Symbol.Index.idata.node(coff); | ||
| 1688 | const import_lookup_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{ | ||
| 1689 | .size = addr_size * 2, | ||
| 1690 | .alignment = addr_align, | ||
| 1691 | .moved = true, | ||
| 1692 | }); | ||
| 1693 | const import_address_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{ | ||
| 1694 | .size = addr_size * 2, | ||
| 1695 | .alignment = addr_align, | ||
| 1696 | .moved = true, | ||
| 1697 | }); | ||
| 1698 | const import_address_table_si = coff.addSymbolAssumeCapacity(); | ||
| 1699 | { | ||
| 1700 | const import_address_table_sym = import_address_table_si.get(coff); | ||
| 1701 | import_address_table_sym.ni = import_address_table_ni; | ||
| 1702 | assert(import_address_table_sym.loc_relocs == .none); | ||
| 1703 | import_address_table_sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | ||
| 1704 | import_address_table_sym.section_number = Symbol.Index.idata.get(coff).section_number; | ||
| 1705 | } | ||
| 1706 | const import_hint_name_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{ | ||
| 1707 | .size = import_hint_name_table_len, | ||
| 1708 | .alignment = import_hint_name_align, | ||
| 1709 | .moved = true, | ||
| 1710 | }); | ||
| 1711 | gop.value_ptr.* = .{ | ||
| 1712 | .import_lookup_table_ni = import_lookup_table_ni, | ||
| 1713 | .import_address_table_si = import_address_table_si, | ||
| 1714 | .import_hint_name_table_ni = import_hint_name_table_ni, | ||
| 1715 | .len = 0, | ||
| 1716 | .hint_name_len = @intCast(import_hint_name_table_len), | ||
| 1717 | }; | ||
| 1718 | const import_hint_name_slice = import_hint_name_table_ni.slice(&coff.mf); | ||
| 1719 | @memcpy(import_hint_name_slice[0..lib_name.len], lib_name); | ||
| 1720 | @memcpy(import_hint_name_slice[lib_name.len..][0..".dll".len], ".dll"); | ||
| 1721 | @memset(import_hint_name_slice[lib_name.len + ".dll".len ..], 0); | ||
| 1722 | coff.nodes.appendAssumeCapacity(.{ .import_lookup_table = @enumFromInt(gop.index) }); | ||
| 1723 | coff.nodes.appendAssumeCapacity(.{ .import_address_table = @enumFromInt(gop.index) }); | ||
| 1724 | coff.nodes.appendAssumeCapacity(.{ .import_hint_name_table = @enumFromInt(gop.index) }); | ||
| 1725 | |||
| 1726 | const import_directory_entries = coff.importDirectoryTableSlice()[gop.index..][0..2]; | ||
| 1727 | import_directory_entries.* = .{ .{ | ||
| 1728 | .import_lookup_table_rva = coff.computeNodeRva(import_lookup_table_ni), | ||
| 1729 | .time_date_stamp = 0, | ||
| 1730 | .forwarder_chain = 0, | ||
| 1731 | .name_rva = coff.computeNodeRva(import_hint_name_table_ni), | ||
| 1732 | .import_address_table_rva = coff.computeNodeRva(import_address_table_ni), | ||
| 1733 | }, .{ | ||
| 1734 | .import_lookup_table_rva = 0, | ||
| 1735 | .time_date_stamp = 0, | ||
| 1736 | .forwarder_chain = 0, | ||
| 1737 | .name_rva = 0, | ||
| 1738 | .import_address_table_rva = 0, | ||
| 1739 | } }; | ||
| 1740 | if (target_endian != native_endian) | ||
| 1741 | std.mem.byteSwapAllFields([2]std.coff.ImportDirectoryEntry, import_directory_entries); | ||
| 1742 | } | ||
| 1743 | const import_symbol_index = gop.value_ptr.len; | ||
| 1744 | gop.value_ptr.len = import_symbol_index + 1; | ||
| 1745 | const new_symbol_table_size = addr_size * (import_symbol_index + 2); | ||
| 1746 | const import_hint_name_index = gop.value_ptr.hint_name_len; | ||
| 1747 | gop.value_ptr.hint_name_len = @intCast( | ||
| 1748 | import_hint_name_align.forward(import_hint_name_index + 2 + name.len + 1), | ||
| 1749 | ); | ||
| 1750 | try gop.value_ptr.import_lookup_table_ni.resize(&coff.mf, gpa, new_symbol_table_size); | ||
| 1751 | const import_address_table_ni = gop.value_ptr.import_address_table_si.node(coff); | ||
| 1752 | try import_address_table_ni.resize(&coff.mf, gpa, new_symbol_table_size); | ||
| 1753 | try gop.value_ptr.import_hint_name_table_ni.resize(&coff.mf, gpa, gop.value_ptr.hint_name_len); | ||
| 1754 | const import_lookup_slice = gop.value_ptr.import_lookup_table_ni.slice(&coff.mf); | ||
| 1755 | const import_address_slice = import_address_table_ni.slice(&coff.mf); | ||
| 1756 | const import_hint_name_slice = gop.value_ptr.import_hint_name_table_ni.slice(&coff.mf); | ||
| 1757 | @memset(import_hint_name_slice[import_hint_name_index..][0..2], 0); | ||
| 1758 | @memcpy(import_hint_name_slice[import_hint_name_index + 2 ..][0..name.len], name); | ||
| 1759 | @memset(import_hint_name_slice[import_hint_name_index + 2 + name.len ..], 0); | ||
| 1760 | const import_hint_name_rva = | ||
| 1761 | coff.computeNodeRva(gop.value_ptr.import_hint_name_table_ni) + import_hint_name_index; | ||
| 1762 | switch (magic) { | ||
| 1763 | _ => unreachable, | ||
| 1764 | inline .PE32, .@"PE32+" => |ct_magic| { | ||
| 1765 | const Addr = switch (ct_magic) { | ||
| 1766 | _ => comptime unreachable, | ||
| 1767 | .PE32 => u32, | ||
| 1768 | .@"PE32+" => u64, | ||
| 1769 | }; | ||
| 1770 | const import_lookup_table: []Addr = @ptrCast(@alignCast(import_lookup_slice)); | ||
| 1771 | const import_address_table: []Addr = @ptrCast(@alignCast(import_address_slice)); | ||
| 1772 | const import_hint_name_rvas: [2]Addr = .{ | ||
| 1773 | std.mem.nativeTo(Addr, @intCast(import_hint_name_rva), target_endian), | ||
| 1774 | std.mem.nativeTo(Addr, 0, target_endian), | ||
| 1775 | }; | ||
| 1776 | import_lookup_table[import_symbol_index..][0..2].* = import_hint_name_rvas; | ||
| 1777 | import_address_table[import_symbol_index..][0..2].* = import_hint_name_rvas; | ||
| 1778 | }, | ||
| 1779 | } | ||
| 1780 | const si = gmi.symbol(coff); | ||
| 1781 | const sym = si.get(coff); | ||
| 1782 | sym.section_number = Symbol.Index.text.get(coff).section_number; | ||
| 1783 | assert(sym.loc_relocs == .none); | ||
| 1784 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | ||
| 1785 | switch (coff.targetLoad(&coff.headerPtr().machine)) { | ||
| 1786 | else => |tag| @panic(@tagName(tag)), | ||
| 1787 | .AMD64 => { | ||
| 1788 | const init = [_]u8{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }; | ||
| 1789 | const target = &comp.root_mod.resolved_target.result; | ||
| 1790 | const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.text.node(coff), .{ | ||
| 1791 | .alignment = switch (comp.root_mod.optimize_mode) { | ||
| 1792 | .Debug, | ||
| 1793 | .ReleaseSafe, | ||
| 1794 | .ReleaseFast, | ||
| 1795 | => target_util.defaultFunctionAlignment(target), | ||
| 1796 | .ReleaseSmall => target_util.minFunctionAlignment(target), | ||
| 1797 | }.toStdMem(), | ||
| 1798 | .size = init.len, | ||
| 1799 | }); | ||
| 1800 | @memcpy(ni.slice(&coff.mf)[0..init.len], &init); | ||
| 1801 | sym.ni = ni; | ||
| 1802 | sym.size = init.len; | ||
| 1803 | try coff.addReloc( | ||
| 1804 | si, | ||
| 1805 | init.len - 4, | ||
| 1806 | gop.value_ptr.import_address_table_si, | ||
| 1807 | @intCast(addr_size * import_symbol_index), | ||
| 1808 | .{ .AMD64 = .REL32 }, | ||
| 1809 | ); | ||
| 1810 | }, | ||
| 1811 | } | ||
| 1812 | coff.nodes.appendAssumeCapacity(.{ .global = gmi }); | ||
| 1813 | sym.rva = coff.computeNodeRva(sym.ni); | ||
| 1814 | si.applyLocationRelocs(coff); | ||
| 1815 | } | ||
| 1816 | } | ||
| 1817 | |||
| 1818 | fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { | ||
| 1819 | const zcu = pt.zcu; | ||
| 1820 | const gpa = zcu.gpa; | ||
| 1821 | |||
| 1822 | const lazy = lmr.lazySymbol(coff); | ||
| 1823 | const si = lmr.symbol(coff); | ||
| 1824 | const ni = ni: { | ||
| 1825 | const sym = si.get(coff); | ||
| 1826 | switch (sym.ni) { | ||
| 1827 | .none => { | ||
| 1828 | try coff.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 1829 | const sec_si: Symbol.Index = switch (lazy.kind) { | ||
| 1830 | .code => .text, | ||
| 1831 | .const_data => .rdata, | ||
| 1832 | }; | ||
| 1833 | const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{ .moved = true }); | ||
| 1834 | coff.nodes.appendAssumeCapacity(switch (lazy.kind) { | ||
| 1835 | .code => .{ .lazy_code = @enumFromInt(lmr.index) }, | ||
| 1836 | .const_data => .{ .lazy_const_data = @enumFromInt(lmr.index) }, | ||
| 1837 | }); | ||
| 1838 | sym.ni = ni; | ||
| 1839 | sym.section_number = sec_si.get(coff).section_number; | ||
| 1840 | }, | ||
| 1841 | else => si.deleteLocationRelocs(coff), | ||
| 1842 | } | ||
| 1843 | assert(sym.loc_relocs == .none); | ||
| 1844 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | ||
| 1845 | break :ni sym.ni; | ||
| 1846 | }; | ||
| 1847 | |||
| 1848 | var required_alignment: InternPool.Alignment = .none; | ||
| 1849 | var nw: MappedFile.Node.Writer = undefined; | ||
| 1850 | ni.writer(&coff.mf, gpa, &nw); | ||
| 1851 | defer nw.deinit(); | ||
| 1852 | try codegen.generateLazySymbol( | ||
| 1853 | &coff.base, | ||
| 1854 | pt, | ||
| 1855 | Type.fromInterned(lazy.ty).srcLocOrNull(pt.zcu) orelse .unneeded, | ||
| 1856 | lazy, | ||
| 1857 | &required_alignment, | ||
| 1858 | &nw.interface, | ||
| 1859 | .none, | ||
| 1860 | .{ .atom_index = @intFromEnum(si) }, | ||
| 1861 | ); | ||
| 1862 | si.get(coff).size = @intCast(nw.interface.end); | ||
| 1863 | si.applyLocationRelocs(coff); | ||
| 1864 | } | ||
| 1865 | |||
| 1866 | fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { | ||
| 1867 | switch (coff.getNode(ni)) { | ||
| 1868 | .file, | ||
| 1869 | .header, | ||
| 1870 | .signature, | ||
| 1871 | .coff_header, | ||
| 1872 | .optional_header, | ||
| 1873 | .data_directories, | ||
| 1874 | .section_table, | ||
| 1875 | => unreachable, | ||
| 1876 | .section => |si| return coff.targetStore( | ||
| 1877 | &si.get(coff).section_number.header(coff).pointer_to_raw_data, | ||
| 1878 | @intCast(ni.fileLocation(&coff.mf, false).offset), | ||
| 1879 | ), | ||
| 1880 | .import_directory_table => coff.targetStore( | ||
| 1881 | &coff.dataDirectoryPtr(.import_table).virtual_address, | ||
| 1882 | coff.computeNodeRva(ni), | ||
| 1883 | ), | ||
| 1884 | .import_lookup_table => |import_index| coff.targetStore( | ||
| 1885 | &coff.importDirectoryEntryPtr(import_index).import_lookup_table_rva, | ||
| 1886 | coff.computeNodeRva(ni), | ||
| 1887 | ), | ||
| 1888 | .import_address_table => |import_index| { | ||
| 1889 | const import_address_table_si = import_index.get(coff).import_address_table_si; | ||
| 1890 | import_address_table_si.flushMoved(coff); | ||
| 1891 | coff.targetStore( | ||
| 1892 | &coff.importDirectoryEntryPtr(import_index).import_address_table_rva, | ||
| 1893 | import_address_table_si.get(coff).rva, | ||
| 1894 | ); | ||
| 1895 | }, | ||
| 1896 | .import_hint_name_table => |import_index| { | ||
| 1897 | const target_endian = coff.targetEndian(); | ||
| 1898 | const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic); | ||
| 1899 | const import_hint_name_rva = coff.computeNodeRva(ni); | ||
| 1900 | coff.targetStore( | ||
| 1901 | &coff.importDirectoryEntryPtr(import_index).name_rva, | ||
| 1902 | import_hint_name_rva, | ||
| 1903 | ); | ||
| 1904 | const import_entry = import_index.get(coff); | ||
| 1905 | const import_lookup_slice = import_entry.import_lookup_table_ni.slice(&coff.mf); | ||
| 1906 | const import_address_slice = | ||
| 1907 | import_entry.import_address_table_si.node(coff).slice(&coff.mf); | ||
| 1908 | const import_hint_name_slice = ni.slice(&coff.mf); | ||
| 1909 | const import_hint_name_align = ni.alignment(&coff.mf); | ||
| 1910 | var import_hint_name_index: u32 = 0; | ||
| 1911 | for (0..import_entry.len) |import_symbol_index| { | ||
| 1912 | import_hint_name_index = @intCast(import_hint_name_align.forward( | ||
| 1913 | std.mem.indexOfScalarPos( | ||
| 1914 | u8, | ||
| 1915 | import_hint_name_slice, | ||
| 1916 | import_hint_name_index, | ||
| 1917 | 0, | ||
| 1918 | ).? + 1, | ||
| 1919 | )); | ||
| 1920 | switch (magic) { | ||
| 1921 | _ => unreachable, | ||
| 1922 | inline .PE32, .@"PE32+" => |ct_magic| { | ||
| 1923 | const Addr = switch (ct_magic) { | ||
| 1924 | _ => comptime unreachable, | ||
| 1925 | .PE32 => u32, | ||
| 1926 | .@"PE32+" => u64, | ||
| 1927 | }; | ||
| 1928 | const import_lookup_table: []Addr = @ptrCast(@alignCast(import_lookup_slice)); | ||
| 1929 | const import_address_table: []Addr = @ptrCast(@alignCast(import_address_slice)); | ||
| 1930 | const rva = std.mem.nativeTo( | ||
| 1931 | Addr, | ||
| 1932 | import_hint_name_rva + import_hint_name_index, | ||
| 1933 | target_endian, | ||
| 1934 | ); | ||
| 1935 | import_lookup_table[import_symbol_index] = rva; | ||
| 1936 | import_address_table[import_symbol_index] = rva; | ||
| 1937 | }, | ||
| 1938 | } | ||
| 1939 | import_hint_name_index += 2; | ||
| 1940 | } | ||
| 1941 | }, | ||
| 1942 | inline .global, | ||
| 1943 | .nav, | ||
| 1944 | .uav, | ||
| 1945 | .lazy_code, | ||
| 1946 | .lazy_const_data, | ||
| 1947 | => |mi| mi.symbol(coff).flushMoved(coff), | ||
| 1948 | } | ||
| 1949 | try ni.childrenMoved(coff.base.comp.gpa, &coff.mf); | ||
| 1950 | } | ||
| 1951 | |||
| 1952 | fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { | ||
| 1953 | _, const size = ni.location(&coff.mf).resolve(&coff.mf); | ||
| 1954 | switch (coff.getNode(ni)) { | ||
| 1955 | .file => {}, | ||
| 1956 | .header => { | ||
| 1957 | switch (coff.optionalHeaderPtr()) { | ||
| 1958 | inline else => |optional_header| coff.targetStore( | ||
| 1959 | &optional_header.size_of_headers, | ||
| 1960 | @intCast(size), | ||
| 1961 | ), | ||
| 1962 | } | ||
| 1963 | if (size > coff.section_table.items[0].get(coff).rva) try coff.virtualSlide( | ||
| 1964 | 0, | ||
| 1965 | std.mem.alignForward( | ||
| 1966 | u32, | ||
| 1967 | @intCast(size * 4), | ||
| 1968 | coff.optionalHeaderField(.section_alignment), | ||
| 1969 | ), | ||
| 1970 | ); | ||
| 1971 | }, | ||
| 1972 | .signature, .coff_header, .optional_header, .data_directories => unreachable, | ||
| 1973 | .section_table => {}, | ||
| 1974 | .section => |si| { | ||
| 1975 | const sym = si.get(coff); | ||
| 1976 | const section_index = sym.section_number.toIndex(); | ||
| 1977 | const section = &coff.sectionTableSlice()[section_index]; | ||
| 1978 | coff.targetStore(&section.size_of_raw_data, @intCast(size)); | ||
| 1979 | if (size > coff.targetLoad(&section.virtual_size)) { | ||
| 1980 | const virtual_size = std.mem.alignForward( | ||
| 1981 | u32, | ||
| 1982 | @intCast(size * 4), | ||
| 1983 | coff.optionalHeaderField(.section_alignment), | ||
| 1984 | ); | ||
| 1985 | coff.targetStore(&section.virtual_size, virtual_size); | ||
| 1986 | try coff.virtualSlide(section_index + 1, sym.rva + virtual_size); | ||
| 1987 | } | ||
| 1988 | }, | ||
| 1989 | .import_directory_table => coff.targetStore( | ||
| 1990 | &coff.dataDirectoryPtr(.import_table).size, | ||
| 1991 | @intCast(size), | ||
| 1992 | ), | ||
| 1993 | .import_lookup_table, | ||
| 1994 | .import_address_table, | ||
| 1995 | .import_hint_name_table, | ||
| 1996 | .global, | ||
| 1997 | .nav, | ||
| 1998 | .uav, | ||
| 1999 | .lazy_code, | ||
| 2000 | .lazy_const_data, | ||
| 2001 | => {}, | ||
| 2002 | } | ||
| 2003 | } | ||
| 2004 | fn virtualSlide(coff: *Coff, start_section_index: usize, start_rva: u32) !void { | ||
| 2005 | var rva = start_rva; | ||
| 2006 | for ( | ||
| 2007 | coff.section_table.items[start_section_index..], | ||
| 2008 | coff.sectionTableSlice()[start_section_index..], | ||
| 2009 | ) |section_si, *section| { | ||
| 2010 | const section_sym = section_si.get(coff); | ||
| 2011 | section_sym.rva = rva; | ||
| 2012 | coff.targetStore(&section.virtual_address, rva); | ||
| 2013 | try section_sym.ni.childrenMoved(coff.base.comp.gpa, &coff.mf); | ||
| 2014 | rva += coff.targetLoad(&section.virtual_size); | ||
| 2015 | } | ||
| 2016 | switch (coff.optionalHeaderPtr()) { | ||
| 2017 | inline else => |optional_header| coff.targetStore( | ||
| 2018 | &optional_header.size_of_image, | ||
| 2019 | @intCast(rva), | ||
| 2020 | ), | ||
| 2021 | } | ||
| 2022 | } | ||
| 2023 | |||
| 2024 | pub fn updateExports( | ||
| 2025 | coff: *Coff, | ||
| 2026 | pt: Zcu.PerThread, | ||
| 2027 | exported: Zcu.Exported, | ||
| 2028 | export_indices: []const Zcu.Export.Index, | ||
| 2029 | ) !void { | ||
| 2030 | return coff.updateExportsInner(pt, exported, export_indices) catch |err| switch (err) { | ||
| 2031 | error.OutOfMemory => error.OutOfMemory, | ||
| 2032 | error.LinkFailure => error.AnalysisFail, | ||
| 2033 | }; | ||
| 2034 | } | ||
| 2035 | fn updateExportsInner( | ||
| 2036 | coff: *Coff, | ||
| 2037 | pt: Zcu.PerThread, | ||
| 2038 | exported: Zcu.Exported, | ||
| 2039 | export_indices: []const Zcu.Export.Index, | ||
| 2040 | ) !void { | ||
| 2041 | const zcu = pt.zcu; | ||
| 2042 | const gpa = zcu.gpa; | ||
| 2043 | const ip = &zcu.intern_pool; | ||
| 2044 | |||
| 2045 | switch (exported) { | ||
| 2046 | .nav => |nav| log.debug("updateExports({f})", .{ip.getNav(nav).fqn.fmt(ip)}), | ||
| 2047 | .uav => |uav| log.debug("updateExports(@as({f}, {f}))", .{ | ||
| 2048 | Type.fromInterned(ip.typeOf(uav)).fmt(pt), | ||
| 2049 | Value.fromInterned(uav).fmtValue(pt), | ||
| 2050 | }), | ||
| 2051 | } | ||
| 2052 | try coff.symbol_table.ensureUnusedCapacity(gpa, export_indices.len); | ||
| 2053 | const exported_si: Symbol.Index = switch (exported) { | ||
| 2054 | .nav => |nav| try coff.navSymbol(zcu, nav), | ||
| 2055 | .uav => |uav| @enumFromInt(switch (try coff.lowerUav( | ||
| 2056 | pt, | ||
| 2057 | uav, | ||
| 2058 | Type.fromInterned(ip.typeOf(uav)).abiAlignment(zcu), | ||
| 2059 | export_indices[0].ptr(zcu).src, | ||
| 2060 | )) { | ||
| 2061 | .sym_index => |si| si, | ||
| 2062 | .fail => |em| { | ||
| 2063 | defer em.destroy(gpa); | ||
| 2064 | return coff.base.comp.link_diags.fail("{s}", .{em.msg}); | ||
| 2065 | }, | ||
| 2066 | }), | ||
| 2067 | }; | ||
| 2068 | while (try coff.idle(pt.tid)) {} | ||
| 2069 | const exported_ni = exported_si.node(coff); | ||
| 2070 | const exported_sym = exported_si.get(coff); | ||
| 2071 | for (export_indices) |export_index| { | ||
| 2072 | const @"export" = export_index.ptr(zcu); | ||
| 2073 | const export_si = try coff.globalSymbol(@"export".opts.name.toSlice(ip), null); | ||
| 2074 | const export_sym = export_si.get(coff); | ||
| 2075 | export_sym.ni = exported_ni; | ||
| 2076 | export_sym.rva = exported_sym.rva; | ||
| 2077 | export_sym.size = exported_sym.size; | ||
| 2078 | export_sym.section_number = exported_sym.section_number; | ||
| 2079 | export_si.applyTargetRelocs(coff); | ||
| 2080 | if (@"export".opts.name.eqlSlice("wWinMainCRTStartup", ip)) { | ||
| 2081 | coff.entry_hack = exported_si; | ||
| 2082 | coff.optionalHeaderStandardPtr().address_of_entry_point = exported_sym.rva; | ||
| 2083 | } | ||
| 2084 | } | ||
| 2085 | } | ||
| 2086 | |||
| 2087 | pub fn deleteExport(coff: *Coff, exported: Zcu.Exported, name: InternPool.NullTerminatedString) void { | ||
| 2088 | _ = coff; | ||
| 2089 | _ = exported; | ||
| 2090 | _ = name; | ||
| 2091 | } | ||
| 2092 | |||
| 2093 | pub fn dump(coff: *Coff, tid: Zcu.PerThread.Id) void { | ||
| 2094 | const w = std.debug.lockStderrWriter(&.{}); | ||
| 2095 | defer std.debug.unlockStderrWriter(); | ||
| 2096 | coff.printNode(tid, w, .root, 0) catch {}; | ||
| 2097 | } | ||
| 2098 | |||
| 2099 | pub fn printNode( | ||
| 2100 | coff: *Coff, | ||
| 2101 | tid: Zcu.PerThread.Id, | ||
| 2102 | w: *std.Io.Writer, | ||
| 2103 | ni: MappedFile.Node.Index, | ||
| 2104 | indent: usize, | ||
| 2105 | ) !void { | ||
| 2106 | const node = coff.getNode(ni); | ||
| 2107 | try w.splatByteAll(' ', indent); | ||
| 2108 | try w.writeAll(@tagName(node)); | ||
| 2109 | switch (node) { | ||
| 2110 | else => {}, | ||
| 2111 | .section => |si| try w.print("({s})", .{ | ||
| 2112 | std.mem.sliceTo(&si.get(coff).section_number.header(coff).name, 0), | ||
| 2113 | }), | ||
| 2114 | .import_lookup_table, | ||
| 2115 | .import_address_table, | ||
| 2116 | .import_hint_name_table, | ||
| 2117 | => |import_index| try w.print("({s})", .{ | ||
| 2118 | std.mem.sliceTo(import_index.get(coff).import_hint_name_table_ni.sliceConst(&coff.mf), 0), | ||
| 2119 | }), | ||
| 2120 | .global => |gmi| { | ||
| 2121 | const gn = gmi.globalName(coff); | ||
| 2122 | try w.writeByte('('); | ||
| 2123 | if (gn.lib_name.toSlice(coff)) |lib_name| try w.print("{s}.dll, ", .{lib_name}); | ||
| 2124 | try w.print("{s})", .{gn.name.toSlice(coff)}); | ||
| 2125 | }, | ||
| 2126 | .nav => |nmi| { | ||
| 2127 | const zcu = coff.base.comp.zcu.?; | ||
| 2128 | const ip = &zcu.intern_pool; | ||
| 2129 | const nav = ip.getNav(nmi.navIndex(coff)); | ||
| 2130 | try w.print("({f}, {f})", .{ | ||
| 2131 | Type.fromInterned(nav.typeOf(ip)).fmt(.{ .zcu = zcu, .tid = tid }), | ||
| 2132 | nav.fqn.fmt(ip), | ||
| 2133 | }); | ||
| 2134 | }, | ||
| 2135 | .uav => |umi| { | ||
| 2136 | const zcu = coff.base.comp.zcu.?; | ||
| 2137 | const val: Value = .fromInterned(umi.uavValue(coff)); | ||
| 2138 | try w.print("({f}, {f})", .{ | ||
| 2139 | val.typeOf(zcu).fmt(.{ .zcu = zcu, .tid = tid }), | ||
| 2140 | val.fmtValue(.{ .zcu = zcu, .tid = tid }), | ||
| 2141 | }); | ||
| 2142 | }, | ||
| 2143 | inline .lazy_code, .lazy_const_data => |lmi| try w.print("({f})", .{ | ||
| 2144 | Type.fromInterned(lmi.lazySymbol(coff).ty).fmt(.{ | ||
| 2145 | .zcu = coff.base.comp.zcu.?, | ||
| 2146 | .tid = tid, | ||
| 2147 | }), | ||
| 2148 | }), | ||
| 2149 | } | ||
| 2150 | { | ||
| 2151 | const mf_node = &coff.mf.nodes.items[@intFromEnum(ni)]; | ||
| 2152 | const off, const size = mf_node.location().resolve(&coff.mf); | ||
| 2153 | try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x}{s}{s}{s}{s}\n", .{ | ||
| 2154 | @intFromEnum(ni), | ||
| 2155 | off, | ||
| 2156 | size, | ||
| 2157 | mf_node.flags.alignment.toByteUnits(), | ||
| 2158 | if (mf_node.flags.fixed) " fixed" else "", | ||
| 2159 | if (mf_node.flags.moved) " moved" else "", | ||
| 2160 | if (mf_node.flags.resized) " resized" else "", | ||
| 2161 | if (mf_node.flags.has_content) " has_content" else "", | ||
| 2162 | }); | ||
| 2163 | } | ||
| 2164 | var leaf = true; | ||
| 2165 | var child_it = ni.children(&coff.mf); | ||
| 2166 | while (child_it.next()) |child_ni| { | ||
| 2167 | leaf = false; | ||
| 2168 | try coff.printNode(tid, w, child_ni, indent + 1); | ||
| 2169 | } | ||
| 2170 | if (leaf) { | ||
| 2171 | const file_loc = ni.fileLocation(&coff.mf, false); | ||
| 2172 | if (file_loc.size == 0) return; | ||
| 2173 | var address = file_loc.offset; | ||
| 2174 | const line_len = 0x10; | ||
| 2175 | var line_it = std.mem.window( | ||
| 2176 | u8, | ||
| 2177 | coff.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)], | ||
| 2178 | line_len, | ||
| 2179 | line_len, | ||
| 2180 | ); | ||
| 2181 | while (line_it.next()) |line_bytes| : (address += line_len) { | ||
| 2182 | try w.splatByteAll(' ', indent + 1); | ||
| 2183 | try w.print("{x:0>8} ", .{address}); | ||
| 2184 | for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte}); | ||
| 2185 | try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1); | ||
| 2186 | for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.'); | ||
| 2187 | try w.writeByte('\n'); | ||
| 2188 | } | ||
| 2189 | } | ||
| 2190 | } | ||
| 2191 | |||
| 2192 | const assert = std.debug.assert; | ||
| 2193 | const builtin = @import("builtin"); | ||
| 2194 | const codegen = @import("../codegen.zig"); | ||
| 2195 | const Compilation = @import("../Compilation.zig"); | ||
| 2196 | const Coff = @This(); | ||
| 2197 | const InternPool = @import("../InternPool.zig"); | ||
| 2198 | const link = @import("../link.zig"); | ||
| 2199 | const log = std.log.scoped(.link); | ||
| 2200 | const MappedFile = @import("MappedFile.zig"); | ||
| 2201 | const native_endian = builtin.cpu.arch.endian(); | ||
| 2202 | const std = @import("std"); | ||
| 2203 | const target_util = @import("../target.zig"); | ||
| 2204 | const Type = @import("../Type.zig"); | ||
| 2205 | const Value = @import("../Value.zig"); | ||
| 2206 | const Zcu = @import("../Zcu.zig"); | ||
src/link/Coff2.zig deleted-2193| ... | @@ -1,2193 +0,0 @@ | ||
| 1 | base: link.File, | ||
| 2 | endian: std.builtin.Endian, | ||
| 3 | mf: MappedFile, | ||
| 4 | nodes: std.MultiArrayList(Node), | ||
| 5 | import_table: ImportTable, | ||
| 6 | strings: std.HashMapUnmanaged( | ||
| 7 | u32, | ||
| 8 | void, | ||
| 9 | std.hash_map.StringIndexContext, | ||
| 10 | std.hash_map.default_max_load_percentage, | ||
| 11 | ), | ||
| 12 | string_bytes: std.ArrayList(u8), | ||
| 13 | section_table: std.ArrayList(Symbol.Index), | ||
| 14 | symbol_table: std.ArrayList(Symbol), | ||
| 15 | globals: std.AutoArrayHashMapUnmanaged(GlobalName, Symbol.Index), | ||
| 16 | global_pending_index: u32, | ||
| 17 | navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index), | ||
| 18 | uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), | ||
| 19 | lazy: std.EnumArray(link.File.LazySymbol.Kind, struct { | ||
| 20 | map: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), | ||
| 21 | pending_index: u32, | ||
| 22 | }), | ||
| 23 | pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct { | ||
| 24 | alignment: InternPool.Alignment, | ||
| 25 | src_loc: Zcu.LazySrcLoc, | ||
| 26 | }), | ||
| 27 | relocs: std.ArrayList(Reloc), | ||
| 28 | /// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly. | ||
| 29 | entry_hack: Symbol.Index, | ||
| 30 | |||
| 31 | pub const default_file_alignment: u16 = 0x200; | ||
| 32 | pub const default_size_of_stack_reserve: u32 = 0x1000000; | ||
| 33 | pub const default_size_of_stack_commit: u32 = 0x1000; | ||
| 34 | pub const default_size_of_heap_reserve: u32 = 0x100000; | ||
| 35 | pub const default_size_of_heap_commit: u32 = 0x1000; | ||
| 36 | |||
| 37 | /// This is the start of a Portable Executable (PE) file. | ||
| 38 | /// It starts with a MS-DOS header followed by a MS-DOS stub program. | ||
| 39 | /// This data does not change so we include it as follows in all binaries. | ||
| 40 | /// | ||
| 41 | /// In this context, | ||
| 42 | /// A "paragraph" is 16 bytes. | ||
| 43 | /// A "page" is 512 bytes. | ||
| 44 | /// A "long" is 4 bytes. | ||
| 45 | /// A "word" is 2 bytes. | ||
| 46 | pub const msdos_stub: [120]u8 = .{ | ||
| 47 | 'M', 'Z', // Magic number. Stands for Mark Zbikowski (designer of the MS-DOS executable format). | ||
| 48 | 0x78, 0x00, // Number of bytes in the last page. This matches the size of this entire MS-DOS stub. | ||
| 49 | 0x01, 0x00, // Number of pages. | ||
| 50 | 0x00, 0x00, // Number of entries in the relocation table. | ||
| 51 | 0x04, 0x00, // The number of paragraphs taken up by the header. 4 * 16 = 64, which matches the header size (all bytes before the MS-DOS stub program). | ||
| 52 | 0x00, 0x00, // The number of paragraphs required by the program. | ||
| 53 | 0x00, 0x00, // The number of paragraphs requested by the program. | ||
| 54 | 0x00, 0x00, // Initial value for SS (relocatable segment address). | ||
| 55 | 0x00, 0x00, // Initial value for SP. | ||
| 56 | 0x00, 0x00, // Checksum. | ||
| 57 | 0x00, 0x00, // Initial value for IP. | ||
| 58 | 0x00, 0x00, // Initial value for CS (relocatable segment address). | ||
| 59 | 0x40, 0x00, // Absolute offset to relocation table. 64 matches the header size (all bytes before the MS-DOS stub program). | ||
| 60 | 0x00, 0x00, // Overlay number. Zero means this is the main executable. | ||
| 61 | } | ||
| 62 | // Reserved words. | ||
| 63 | ++ .{ 0x00, 0x00 } ** 4 | ||
| 64 | // OEM-related fields. | ||
| 65 | ++ .{ | ||
| 66 | 0x00, 0x00, // OEM identifier. | ||
| 67 | 0x00, 0x00, // OEM information. | ||
| 68 | } | ||
| 69 | // Reserved words. | ||
| 70 | ++ .{ 0x00, 0x00 } ** 10 | ||
| 71 | // Address of the PE header (a long). This matches the size of this entire MS-DOS stub, so that's the address of what's after this MS-DOS stub. | ||
| 72 | ++ .{ 0x78, 0x00, 0x00, 0x00 } | ||
| 73 | // What follows is a 16-bit x86 MS-DOS program of 7 instructions that prints the bytes after these instructions and then exits. | ||
| 74 | ++ .{ | ||
| 75 | // Set the value of the data segment to the same value as the code segment. | ||
| 76 | 0x0e, // push cs | ||
| 77 | 0x1f, // pop ds | ||
| 78 | // Set the DX register to the address of the message. | ||
| 79 | // If you count all bytes of these 7 instructions you get 14, so that's the address of what's after these instructions. | ||
| 80 | 0xba, 14, 0x00, // mov dx, 14 | ||
| 81 | // Set AH to the system call code for printing a message. | ||
| 82 | 0xb4, 0x09, // mov ah, 0x09 | ||
| 83 | // Perform the system call to print the message. | ||
| 84 | 0xcd, 0x21, // int 0x21 | ||
| 85 | // Set AH to 0x4c which is the system call code for exiting, and set AL to 0x01 which is the exit code. | ||
| 86 | 0xb8, 0x01, 0x4c, // mov ax, 0x4c01 | ||
| 87 | // Peform the system call to exit the program with exit code 1. | ||
| 88 | 0xcd, 0x21, // int 0x21 | ||
| 89 | } | ||
| 90 | // Message to print. | ||
| 91 | ++ "This program cannot be run in DOS mode.".* | ||
| 92 | // Message terminators. | ||
| 93 | ++ .{ | ||
| 94 | '$', // We do not pass a length to the print system call; the string is terminated by this character. | ||
| 95 | 0x00, 0x00, // Terminating zero bytes. | ||
| 96 | }; | ||
| 97 | |||
| 98 | pub const Node = union(enum) { | ||
| 99 | file, | ||
| 100 | header, | ||
| 101 | signature, | ||
| 102 | coff_header, | ||
| 103 | optional_header, | ||
| 104 | data_directories, | ||
| 105 | section_table, | ||
| 106 | section: Symbol.Index, | ||
| 107 | import_directory_table, | ||
| 108 | import_lookup_table: u32, | ||
| 109 | import_address_table: u32, | ||
| 110 | import_hint_name_table: u32, | ||
| 111 | global: GlobalMapIndex, | ||
| 112 | nav: NavMapIndex, | ||
| 113 | uav: UavMapIndex, | ||
| 114 | lazy_code: LazyMapRef.Index(.code), | ||
| 115 | lazy_const_data: LazyMapRef.Index(.const_data), | ||
| 116 | |||
| 117 | pub const GlobalMapIndex = enum(u32) { | ||
| 118 | _, | ||
| 119 | |||
| 120 | pub fn globalName(gmi: GlobalMapIndex, coff: *const Coff) GlobalName { | ||
| 121 | return coff.globals.keys()[@intFromEnum(gmi)]; | ||
| 122 | } | ||
| 123 | |||
| 124 | pub fn symbol(gmi: GlobalMapIndex, coff: *const Coff) Symbol.Index { | ||
| 125 | return coff.globals.values()[@intFromEnum(gmi)]; | ||
| 126 | } | ||
| 127 | }; | ||
| 128 | |||
| 129 | pub const NavMapIndex = enum(u32) { | ||
| 130 | _, | ||
| 131 | |||
| 132 | pub fn navIndex(nmi: NavMapIndex, coff: *const Coff) InternPool.Nav.Index { | ||
| 133 | return coff.navs.keys()[@intFromEnum(nmi)]; | ||
| 134 | } | ||
| 135 | |||
| 136 | pub fn symbol(nmi: NavMapIndex, coff: *const Coff) Symbol.Index { | ||
| 137 | return coff.navs.values()[@intFromEnum(nmi)]; | ||
| 138 | } | ||
| 139 | }; | ||
| 140 | |||
| 141 | pub const UavMapIndex = enum(u32) { | ||
| 142 | _, | ||
| 143 | |||
| 144 | pub fn uavValue(umi: UavMapIndex, coff: *const Coff) InternPool.Index { | ||
| 145 | return coff.uavs.keys()[@intFromEnum(umi)]; | ||
| 146 | } | ||
| 147 | |||
| 148 | pub fn symbol(umi: UavMapIndex, coff: *const Coff) Symbol.Index { | ||
| 149 | return coff.uavs.values()[@intFromEnum(umi)]; | ||
| 150 | } | ||
| 151 | }; | ||
| 152 | |||
| 153 | pub const LazyMapRef = struct { | ||
| 154 | kind: link.File.LazySymbol.Kind, | ||
| 155 | index: u32, | ||
| 156 | |||
| 157 | pub fn Index(comptime kind: link.File.LazySymbol.Kind) type { | ||
| 158 | return enum(u32) { | ||
| 159 | _, | ||
| 160 | |||
| 161 | pub fn ref(lmi: @This()) LazyMapRef { | ||
| 162 | return .{ .kind = kind, .index = @intFromEnum(lmi) }; | ||
| 163 | } | ||
| 164 | |||
| 165 | pub fn lazySymbol(lmi: @This(), coff: *const Coff) link.File.LazySymbol { | ||
| 166 | return lmi.ref().lazySymbol(coff); | ||
| 167 | } | ||
| 168 | |||
| 169 | pub fn symbol(lmi: @This(), coff: *const Coff) Symbol.Index { | ||
| 170 | return lmi.ref().symbol(coff); | ||
| 171 | } | ||
| 172 | }; | ||
| 173 | } | ||
| 174 | |||
| 175 | pub fn lazySymbol(lmr: LazyMapRef, coff: *const Coff) link.File.LazySymbol { | ||
| 176 | return .{ .kind = lmr.kind, .ty = coff.lazy.getPtrConst(lmr.kind).map.keys()[lmr.index] }; | ||
| 177 | } | ||
| 178 | |||
| 179 | pub fn symbol(lmr: LazyMapRef, coff: *const Coff) Symbol.Index { | ||
| 180 | return coff.lazy.getPtrConst(lmr.kind).map.values()[lmr.index]; | ||
| 181 | } | ||
| 182 | }; | ||
| 183 | |||
| 184 | pub const Tag = @typeInfo(Node).@"union".tag_type.?; | ||
| 185 | |||
| 186 | const known_count = @typeInfo(@TypeOf(known)).@"struct".fields.len; | ||
| 187 | const known = known: { | ||
| 188 | const Known = enum { | ||
| 189 | file, | ||
| 190 | header, | ||
| 191 | signature, | ||
| 192 | coff_header, | ||
| 193 | optional_header, | ||
| 194 | data_directories, | ||
| 195 | section_table, | ||
| 196 | }; | ||
| 197 | var mut_known: std.enums.EnumFieldStruct(Known, MappedFile.Node.Index, null) = undefined; | ||
| 198 | for (@typeInfo(Known).@"enum".fields) |field| | ||
| 199 | @field(mut_known, field.name) = @enumFromInt(field.value); | ||
| 200 | break :known mut_known; | ||
| 201 | }; | ||
| 202 | |||
| 203 | comptime { | ||
| 204 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Node) == 8); | ||
| 205 | } | ||
| 206 | }; | ||
| 207 | |||
| 208 | pub const DataDirectory = enum { | ||
| 209 | export_table, | ||
| 210 | import_table, | ||
| 211 | resorce_table, | ||
| 212 | exception_table, | ||
| 213 | certificate_table, | ||
| 214 | base_relocation_table, | ||
| 215 | debug, | ||
| 216 | architecture, | ||
| 217 | global_ptr, | ||
| 218 | tls_table, | ||
| 219 | load_config_table, | ||
| 220 | bound_import, | ||
| 221 | import_address_table, | ||
| 222 | delay_import_descriptor, | ||
| 223 | clr_runtime_header, | ||
| 224 | reserved, | ||
| 225 | }; | ||
| 226 | |||
| 227 | pub const ImportTable = struct { | ||
| 228 | directory_table_ni: MappedFile.Node.Index, | ||
| 229 | dlls: std.AutoArrayHashMapUnmanaged(void, Dll), | ||
| 230 | |||
| 231 | pub const Dll = struct { | ||
| 232 | import_lookup_table_ni: MappedFile.Node.Index, | ||
| 233 | import_address_table_si: Symbol.Index, | ||
| 234 | import_hint_name_table_ni: MappedFile.Node.Index, | ||
| 235 | len: u32, | ||
| 236 | hint_name_len: u32, | ||
| 237 | }; | ||
| 238 | |||
| 239 | const Adapter = struct { | ||
| 240 | coff: *Coff, | ||
| 241 | |||
| 242 | pub fn eql(adapter: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool { | ||
| 243 | const coff = adapter.coff; | ||
| 244 | const dll_name = coff.import_table.dlls.values()[rhs_index] | ||
| 245 | .import_hint_name_table_ni.sliceConst(&coff.mf); | ||
| 246 | return std.mem.startsWith(u8, dll_name, lhs_key) and | ||
| 247 | std.mem.startsWith(u8, dll_name[lhs_key.len..], ".dll\x00"); | ||
| 248 | } | ||
| 249 | |||
| 250 | pub fn hash(_: Adapter, key: []const u8) u32 { | ||
| 251 | assert(std.mem.indexOfScalar(u8, key, 0) == null); | ||
| 252 | return std.array_hash_map.hashString(key); | ||
| 253 | } | ||
| 254 | }; | ||
| 255 | }; | ||
| 256 | |||
| 257 | pub const String = enum(u32) { | ||
| 258 | _, | ||
| 259 | |||
| 260 | pub const Optional = enum(u32) { | ||
| 261 | none = std.math.maxInt(u32), | ||
| 262 | _, | ||
| 263 | |||
| 264 | pub fn unwrap(os: String.Optional) ?String { | ||
| 265 | return switch (os) { | ||
| 266 | else => |s| @enumFromInt(@intFromEnum(s)), | ||
| 267 | .none => null, | ||
| 268 | }; | ||
| 269 | } | ||
| 270 | |||
| 271 | pub fn toSlice(os: String.Optional, coff: *Coff) ?[:0]const u8 { | ||
| 272 | return (os.unwrap() orelse return null).toSlice(coff); | ||
| 273 | } | ||
| 274 | }; | ||
| 275 | |||
| 276 | pub fn toSlice(s: String, coff: *Coff) [:0]const u8 { | ||
| 277 | const slice = coff.string_bytes.items[@intFromEnum(s)..]; | ||
| 278 | return slice[0..std.mem.indexOfScalar(u8, slice, 0).? :0]; | ||
| 279 | } | ||
| 280 | |||
| 281 | pub fn toOptional(s: String) String.Optional { | ||
| 282 | return @enumFromInt(@intFromEnum(s)); | ||
| 283 | } | ||
| 284 | }; | ||
| 285 | |||
| 286 | pub const GlobalName = struct { name: String, lib_name: String.Optional }; | ||
| 287 | |||
| 288 | pub const Symbol = struct { | ||
| 289 | ni: MappedFile.Node.Index, | ||
| 290 | rva: u32, | ||
| 291 | size: u32, | ||
| 292 | /// Relocations contained within this symbol | ||
| 293 | loc_relocs: Reloc.Index, | ||
| 294 | /// Relocations targeting this symbol | ||
| 295 | target_relocs: Reloc.Index, | ||
| 296 | section_number: SectionNumber, | ||
| 297 | data_directory: ?DataDirectory, | ||
| 298 | unused0: u32 = 0, | ||
| 299 | unused1: u32 = 0, | ||
| 300 | |||
| 301 | pub const SectionNumber = enum(i16) { | ||
| 302 | UNDEFINED = 0, | ||
| 303 | ABSOLUTE = -1, | ||
| 304 | DEBUG = -2, | ||
| 305 | _, | ||
| 306 | |||
| 307 | fn toIndex(sn: SectionNumber) u15 { | ||
| 308 | return @intCast(@intFromEnum(sn) - 1); | ||
| 309 | } | ||
| 310 | |||
| 311 | pub fn symbol(sn: SectionNumber, coff: *const Coff) Symbol.Index { | ||
| 312 | return coff.section_table.items[sn.toIndex()]; | ||
| 313 | } | ||
| 314 | |||
| 315 | pub fn header(sn: SectionNumber, coff: *Coff) *std.coff.SectionHeader { | ||
| 316 | return &coff.sectionTableSlice()[sn.toIndex()]; | ||
| 317 | } | ||
| 318 | }; | ||
| 319 | |||
| 320 | pub const Index = enum(u32) { | ||
| 321 | null, | ||
| 322 | data, | ||
| 323 | idata, | ||
| 324 | rdata, | ||
| 325 | text, | ||
| 326 | _, | ||
| 327 | |||
| 328 | const known_count = @typeInfo(Index).@"enum".fields.len; | ||
| 329 | |||
| 330 | pub fn get(si: Symbol.Index, coff: *Coff) *Symbol { | ||
| 331 | return &coff.symbol_table.items[@intFromEnum(si)]; | ||
| 332 | } | ||
| 333 | |||
| 334 | pub fn node(si: Symbol.Index, coff: *Coff) MappedFile.Node.Index { | ||
| 335 | const ni = si.get(coff).ni; | ||
| 336 | assert(ni != .none); | ||
| 337 | return ni; | ||
| 338 | } | ||
| 339 | |||
| 340 | pub fn flushMoved(si: Symbol.Index, coff: *Coff) void { | ||
| 341 | const sym = si.get(coff); | ||
| 342 | sym.rva = coff.computeNodeRva(sym.ni); | ||
| 343 | if (si == coff.entry_hack) | ||
| 344 | coff.targetStore(&coff.optionalHeaderStandardPtr().address_of_entry_point, sym.rva); | ||
| 345 | si.applyLocationRelocs(coff); | ||
| 346 | si.applyTargetRelocs(coff); | ||
| 347 | } | ||
| 348 | |||
| 349 | pub fn applyLocationRelocs(si: Symbol.Index, coff: *Coff) void { | ||
| 350 | for (coff.relocs.items[@intFromEnum(si.get(coff).loc_relocs)..]) |*reloc| { | ||
| 351 | if (reloc.loc != si) break; | ||
| 352 | reloc.apply(coff); | ||
| 353 | } | ||
| 354 | } | ||
| 355 | |||
| 356 | pub fn applyTargetRelocs(si: Symbol.Index, coff: *Coff) void { | ||
| 357 | var ri = si.get(coff).target_relocs; | ||
| 358 | while (ri != .none) { | ||
| 359 | const reloc = ri.get(coff); | ||
| 360 | assert(reloc.target == si); | ||
| 361 | reloc.apply(coff); | ||
| 362 | ri = reloc.next; | ||
| 363 | } | ||
| 364 | } | ||
| 365 | |||
| 366 | pub fn deleteLocationRelocs(si: Symbol.Index, coff: *Coff) void { | ||
| 367 | const sym = si.get(coff); | ||
| 368 | for (coff.relocs.items[@intFromEnum(sym.loc_relocs)..]) |*reloc| { | ||
| 369 | if (reloc.loc != si) break; | ||
| 370 | reloc.delete(coff); | ||
| 371 | } | ||
| 372 | sym.loc_relocs = .none; | ||
| 373 | } | ||
| 374 | }; | ||
| 375 | |||
| 376 | comptime { | ||
| 377 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 32); | ||
| 378 | } | ||
| 379 | }; | ||
| 380 | |||
| 381 | pub const Reloc = extern struct { | ||
| 382 | type: Reloc.Type, | ||
| 383 | prev: Reloc.Index, | ||
| 384 | next: Reloc.Index, | ||
| 385 | loc: Symbol.Index, | ||
| 386 | target: Symbol.Index, | ||
| 387 | unused: u32, | ||
| 388 | offset: u64, | ||
| 389 | addend: i64, | ||
| 390 | |||
| 391 | pub const Type = extern union { | ||
| 392 | AMD64: std.coff.IMAGE.REL.AMD64, | ||
| 393 | ARM: std.coff.IMAGE.REL.ARM, | ||
| 394 | ARM64: std.coff.IMAGE.REL.ARM64, | ||
| 395 | SH: std.coff.IMAGE.REL.SH, | ||
| 396 | PPC: std.coff.IMAGE.REL.PPC, | ||
| 397 | I386: std.coff.IMAGE.REL.I386, | ||
| 398 | IA64: std.coff.IMAGE.REL.IA64, | ||
| 399 | MIPS: std.coff.IMAGE.REL.MIPS, | ||
| 400 | M32R: std.coff.IMAGE.REL.M32R, | ||
| 401 | }; | ||
| 402 | |||
| 403 | pub const Index = enum(u32) { | ||
| 404 | none = std.math.maxInt(u32), | ||
| 405 | _, | ||
| 406 | |||
| 407 | pub fn get(si: Reloc.Index, coff: *Coff) *Reloc { | ||
| 408 | return &coff.relocs.items[@intFromEnum(si)]; | ||
| 409 | } | ||
| 410 | }; | ||
| 411 | |||
| 412 | pub fn apply(reloc: *const Reloc, coff: *Coff) void { | ||
| 413 | const loc_sym = reloc.loc.get(coff); | ||
| 414 | switch (loc_sym.ni) { | ||
| 415 | .none => return, | ||
| 416 | else => |ni| if (ni.hasMoved(&coff.mf)) return, | ||
| 417 | } | ||
| 418 | const target_sym = reloc.target.get(coff); | ||
| 419 | switch (target_sym.ni) { | ||
| 420 | .none => return, | ||
| 421 | else => |ni| if (ni.hasMoved(&coff.mf)) return, | ||
| 422 | } | ||
| 423 | const loc_slice = loc_sym.ni.slice(&coff.mf)[@intCast(reloc.offset)..]; | ||
| 424 | const target_rva = target_sym.rva +% @as(u64, @bitCast(reloc.addend)); | ||
| 425 | const target_endian = coff.targetEndian(); | ||
| 426 | switch (coff.targetLoad(&coff.headerPtr().machine)) { | ||
| 427 | else => |machine| @panic(@tagName(machine)), | ||
| 428 | .AMD64 => switch (reloc.type.AMD64) { | ||
| 429 | else => |kind| @panic(@tagName(kind)), | ||
| 430 | .ABSOLUTE => {}, | ||
| 431 | .ADDR64 => std.mem.writeInt( | ||
| 432 | u64, | ||
| 433 | loc_slice[0..8], | ||
| 434 | coff.optionalHeaderField(.image_base) + target_rva, | ||
| 435 | target_endian, | ||
| 436 | ), | ||
| 437 | .ADDR32 => std.mem.writeInt( | ||
| 438 | u32, | ||
| 439 | loc_slice[0..4], | ||
| 440 | @intCast(coff.optionalHeaderField(.image_base) + target_rva), | ||
| 441 | target_endian, | ||
| 442 | ), | ||
| 443 | .ADDR32NB => std.mem.writeInt( | ||
| 444 | u32, | ||
| 445 | loc_slice[0..4], | ||
| 446 | @intCast(target_rva), | ||
| 447 | target_endian, | ||
| 448 | ), | ||
| 449 | .REL32 => std.mem.writeInt( | ||
| 450 | i32, | ||
| 451 | loc_slice[0..4], | ||
| 452 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 4)))), | ||
| 453 | target_endian, | ||
| 454 | ), | ||
| 455 | .REL32_1 => std.mem.writeInt( | ||
| 456 | i32, | ||
| 457 | loc_slice[0..4], | ||
| 458 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 5)))), | ||
| 459 | target_endian, | ||
| 460 | ), | ||
| 461 | .REL32_2 => std.mem.writeInt( | ||
| 462 | i32, | ||
| 463 | loc_slice[0..4], | ||
| 464 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 6)))), | ||
| 465 | target_endian, | ||
| 466 | ), | ||
| 467 | .REL32_3 => std.mem.writeInt( | ||
| 468 | i32, | ||
| 469 | loc_slice[0..4], | ||
| 470 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 7)))), | ||
| 471 | target_endian, | ||
| 472 | ), | ||
| 473 | .REL32_4 => std.mem.writeInt( | ||
| 474 | i32, | ||
| 475 | loc_slice[0..4], | ||
| 476 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 8)))), | ||
| 477 | target_endian, | ||
| 478 | ), | ||
| 479 | .REL32_5 => std.mem.writeInt( | ||
| 480 | i32, | ||
| 481 | loc_slice[0..4], | ||
| 482 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 9)))), | ||
| 483 | target_endian, | ||
| 484 | ), | ||
| 485 | }, | ||
| 486 | .I386 => switch (reloc.type.I386) { | ||
| 487 | else => |kind| @panic(@tagName(kind)), | ||
| 488 | .ABSOLUTE => {}, | ||
| 489 | .DIR16 => std.mem.writeInt( | ||
| 490 | u16, | ||
| 491 | loc_slice[0..2], | ||
| 492 | @intCast(coff.optionalHeaderField(.image_base) + target_rva), | ||
| 493 | target_endian, | ||
| 494 | ), | ||
| 495 | .REL16 => std.mem.writeInt( | ||
| 496 | i16, | ||
| 497 | loc_slice[0..2], | ||
| 498 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 2)))), | ||
| 499 | target_endian, | ||
| 500 | ), | ||
| 501 | .DIR32 => std.mem.writeInt( | ||
| 502 | u32, | ||
| 503 | loc_slice[0..4], | ||
| 504 | @intCast(coff.optionalHeaderField(.image_base) + target_rva), | ||
| 505 | target_endian, | ||
| 506 | ), | ||
| 507 | .DIR32NB => std.mem.writeInt( | ||
| 508 | u32, | ||
| 509 | loc_slice[0..4], | ||
| 510 | @intCast(target_rva), | ||
| 511 | target_endian, | ||
| 512 | ), | ||
| 513 | .REL32 => std.mem.writeInt( | ||
| 514 | i32, | ||
| 515 | loc_slice[0..4], | ||
| 516 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 4)))), | ||
| 517 | target_endian, | ||
| 518 | ), | ||
| 519 | }, | ||
| 520 | } | ||
| 521 | } | ||
| 522 | |||
| 523 | pub fn delete(reloc: *Reloc, coff: *Coff) void { | ||
| 524 | switch (reloc.prev) { | ||
| 525 | .none => { | ||
| 526 | const target = reloc.target.get(coff); | ||
| 527 | assert(target.target_relocs.get(coff) == reloc); | ||
| 528 | target.target_relocs = reloc.next; | ||
| 529 | }, | ||
| 530 | else => |prev| prev.get(coff).next = reloc.next, | ||
| 531 | } | ||
| 532 | switch (reloc.next) { | ||
| 533 | .none => {}, | ||
| 534 | else => |next| next.get(coff).prev = reloc.prev, | ||
| 535 | } | ||
| 536 | reloc.* = undefined; | ||
| 537 | } | ||
| 538 | |||
| 539 | comptime { | ||
| 540 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Reloc) == 40); | ||
| 541 | } | ||
| 542 | }; | ||
| 543 | |||
| 544 | pub fn open( | ||
| 545 | arena: std.mem.Allocator, | ||
| 546 | comp: *Compilation, | ||
| 547 | path: std.Build.Cache.Path, | ||
| 548 | options: link.File.OpenOptions, | ||
| 549 | ) !*Coff { | ||
| 550 | return create(arena, comp, path, options); | ||
| 551 | } | ||
| 552 | pub fn createEmpty( | ||
| 553 | arena: std.mem.Allocator, | ||
| 554 | comp: *Compilation, | ||
| 555 | path: std.Build.Cache.Path, | ||
| 556 | options: link.File.OpenOptions, | ||
| 557 | ) !*Coff { | ||
| 558 | return create(arena, comp, path, options); | ||
| 559 | } | ||
| 560 | fn create( | ||
| 561 | arena: std.mem.Allocator, | ||
| 562 | comp: *Compilation, | ||
| 563 | path: std.Build.Cache.Path, | ||
| 564 | options: link.File.OpenOptions, | ||
| 565 | ) !*Coff { | ||
| 566 | const target = &comp.root_mod.resolved_target.result; | ||
| 567 | assert(target.ofmt == .coff); | ||
| 568 | const is_image = switch (comp.config.output_mode) { | ||
| 569 | .Exe => true, | ||
| 570 | .Lib => switch (comp.config.link_mode) { | ||
| 571 | .static => false, | ||
| 572 | .dynamic => true, | ||
| 573 | }, | ||
| 574 | .Obj => false, | ||
| 575 | }; | ||
| 576 | const machine = target.toCoffMachine(); | ||
| 577 | const timestamp: u32 = if (options.repro) 0 else @truncate(@as(u64, @bitCast(std.time.timestamp()))); | ||
| 578 | const major_subsystem_version = options.major_subsystem_version orelse 6; | ||
| 579 | const minor_subsystem_version = options.minor_subsystem_version orelse 0; | ||
| 580 | const magic: std.coff.OptionalHeader.Magic = switch (target.ptrBitWidth()) { | ||
| 581 | 0...32 => .PE32, | ||
| 582 | 33...64 => .@"PE32+", | ||
| 583 | else => return error.UnsupportedCOFFArchitecture, | ||
| 584 | }; | ||
| 585 | const section_align: std.mem.Alignment = switch (machine) { | ||
| 586 | .AMD64, .I386 => @enumFromInt(12), | ||
| 587 | .SH3, .SH3DSP, .SH4, .SH5 => @enumFromInt(12), | ||
| 588 | .MIPS16, .MIPSFPU, .MIPSFPU16, .WCEMIPSV2 => @enumFromInt(12), | ||
| 589 | .POWERPC, .POWERPCFP => @enumFromInt(12), | ||
| 590 | .ALPHA, .ALPHA64 => @enumFromInt(13), | ||
| 591 | .IA64 => @enumFromInt(13), | ||
| 592 | .ARM => @enumFromInt(12), | ||
| 593 | else => return error.UnsupportedCOFFArchitecture, | ||
| 594 | }; | ||
| 595 | |||
| 596 | const coff = try arena.create(Coff); | ||
| 597 | const file = try path.root_dir.handle.createFile(path.sub_path, .{ | ||
| 598 | .read = true, | ||
| 599 | .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode), | ||
| 600 | }); | ||
| 601 | errdefer file.close(); | ||
| 602 | coff.* = .{ | ||
| 603 | .base = .{ | ||
| 604 | .tag = .coff2, | ||
| 605 | |||
| 606 | .comp = comp, | ||
| 607 | .emit = path, | ||
| 608 | |||
| 609 | .file = file, | ||
| 610 | .gc_sections = false, | ||
| 611 | .print_gc_sections = false, | ||
| 612 | .build_id = .none, | ||
| 613 | .allow_shlib_undefined = false, | ||
| 614 | .stack_size = 0, | ||
| 615 | }, | ||
| 616 | .endian = target.cpu.arch.endian(), | ||
| 617 | .mf = try .init(file, comp.gpa), | ||
| 618 | .nodes = .empty, | ||
| 619 | .import_table = .{ | ||
| 620 | .directory_table_ni = .none, | ||
| 621 | .dlls = .empty, | ||
| 622 | }, | ||
| 623 | .strings = .empty, | ||
| 624 | .string_bytes = .empty, | ||
| 625 | .section_table = .empty, | ||
| 626 | .symbol_table = .empty, | ||
| 627 | .globals = .empty, | ||
| 628 | .global_pending_index = 0, | ||
| 629 | .navs = .empty, | ||
| 630 | .uavs = .empty, | ||
| 631 | .lazy = .initFill(.{ | ||
| 632 | .map = .empty, | ||
| 633 | .pending_index = 0, | ||
| 634 | }), | ||
| 635 | .pending_uavs = .empty, | ||
| 636 | .relocs = .empty, | ||
| 637 | .entry_hack = .null, | ||
| 638 | }; | ||
| 639 | errdefer coff.deinit(); | ||
| 640 | |||
| 641 | try coff.initHeaders( | ||
| 642 | is_image, | ||
| 643 | machine, | ||
| 644 | timestamp, | ||
| 645 | major_subsystem_version, | ||
| 646 | minor_subsystem_version, | ||
| 647 | magic, | ||
| 648 | section_align, | ||
| 649 | ); | ||
| 650 | return coff; | ||
| 651 | } | ||
| 652 | |||
| 653 | pub fn deinit(coff: *Coff) void { | ||
| 654 | const gpa = coff.base.comp.gpa; | ||
| 655 | coff.mf.deinit(gpa); | ||
| 656 | coff.nodes.deinit(gpa); | ||
| 657 | coff.import_table.dlls.deinit(gpa); | ||
| 658 | coff.strings.deinit(gpa); | ||
| 659 | coff.string_bytes.deinit(gpa); | ||
| 660 | coff.section_table.deinit(gpa); | ||
| 661 | coff.symbol_table.deinit(gpa); | ||
| 662 | coff.globals.deinit(gpa); | ||
| 663 | coff.navs.deinit(gpa); | ||
| 664 | coff.uavs.deinit(gpa); | ||
| 665 | for (&coff.lazy.values) |*lazy| lazy.map.deinit(gpa); | ||
| 666 | coff.pending_uavs.deinit(gpa); | ||
| 667 | coff.relocs.deinit(gpa); | ||
| 668 | coff.* = undefined; | ||
| 669 | } | ||
| 670 | |||
| 671 | fn initHeaders( | ||
| 672 | coff: *Coff, | ||
| 673 | is_image: bool, | ||
| 674 | machine: std.coff.IMAGE.FILE.MACHINE, | ||
| 675 | timestamp: u32, | ||
| 676 | major_subsystem_version: u16, | ||
| 677 | minor_subsystem_version: u16, | ||
| 678 | magic: std.coff.OptionalHeader.Magic, | ||
| 679 | section_align: std.mem.Alignment, | ||
| 680 | ) !void { | ||
| 681 | const comp = coff.base.comp; | ||
| 682 | const gpa = comp.gpa; | ||
| 683 | const file_align: std.mem.Alignment = comptime .fromByteUnits(default_file_alignment); | ||
| 684 | const target_endian = coff.targetEndian(); | ||
| 685 | |||
| 686 | const optional_header_size: u16 = if (is_image) switch (magic) { | ||
| 687 | _ => unreachable, | ||
| 688 | inline else => |ct_magic| @sizeOf(@field(std.coff.OptionalHeader, @tagName(ct_magic))), | ||
| 689 | } else 0; | ||
| 690 | const data_directories_len = @typeInfo(DataDirectory).@"enum".fields.len; | ||
| 691 | const data_directories_size: u16 = if (is_image) | ||
| 692 | @sizeOf(std.coff.ImageDataDirectory) * data_directories_len | ||
| 693 | else | ||
| 694 | 0; | ||
| 695 | |||
| 696 | try coff.nodes.ensureTotalCapacity(gpa, Node.known_count); | ||
| 697 | coff.nodes.appendAssumeCapacity(.file); | ||
| 698 | |||
| 699 | const header_ni = Node.known.header; | ||
| 700 | assert(header_ni == try coff.mf.addOnlyChildNode(gpa, .root, .{ | ||
| 701 | .alignment = coff.mf.flags.block_size, | ||
| 702 | .fixed = true, | ||
| 703 | })); | ||
| 704 | coff.nodes.appendAssumeCapacity(.header); | ||
| 705 | |||
| 706 | const signature_ni = Node.known.signature; | ||
| 707 | assert(signature_ni == try coff.mf.addOnlyChildNode(gpa, header_ni, .{ | ||
| 708 | .size = (if (is_image) msdos_stub.len else 0) + "PE\x00\x00".len, | ||
| 709 | .alignment = .@"4", | ||
| 710 | .fixed = true, | ||
| 711 | })); | ||
| 712 | coff.nodes.appendAssumeCapacity(.signature); | ||
| 713 | { | ||
| 714 | const signature_slice = signature_ni.slice(&coff.mf); | ||
| 715 | if (is_image) @memcpy(signature_slice[0..msdos_stub.len], &msdos_stub); | ||
| 716 | @memcpy(signature_slice[signature_slice.len - 4 ..], "PE\x00\x00"); | ||
| 717 | } | ||
| 718 | |||
| 719 | const coff_header_ni = Node.known.coff_header; | ||
| 720 | assert(coff_header_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ | ||
| 721 | .size = @sizeOf(std.coff.Header), | ||
| 722 | .alignment = .@"4", | ||
| 723 | .fixed = true, | ||
| 724 | })); | ||
| 725 | coff.nodes.appendAssumeCapacity(.coff_header); | ||
| 726 | { | ||
| 727 | const coff_header: *std.coff.Header = @ptrCast(@alignCast(coff_header_ni.slice(&coff.mf))); | ||
| 728 | coff_header.* = .{ | ||
| 729 | .machine = machine, | ||
| 730 | .number_of_sections = 0, | ||
| 731 | .time_date_stamp = timestamp, | ||
| 732 | .pointer_to_symbol_table = 0, | ||
| 733 | .number_of_symbols = 0, | ||
| 734 | .size_of_optional_header = optional_header_size + data_directories_size, | ||
| 735 | .flags = .{ | ||
| 736 | .RELOCS_STRIPPED = is_image, | ||
| 737 | .EXECUTABLE_IMAGE = is_image, | ||
| 738 | .DEBUG_STRIPPED = true, | ||
| 739 | .@"32BIT_MACHINE" = magic == .PE32, | ||
| 740 | .LARGE_ADDRESS_AWARE = magic == .@"PE32+", | ||
| 741 | .DLL = comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic, | ||
| 742 | }, | ||
| 743 | }; | ||
| 744 | if (target_endian != native_endian) std.mem.byteSwapAllFields(std.coff.Header, coff_header); | ||
| 745 | } | ||
| 746 | |||
| 747 | const optional_header_ni = Node.known.optional_header; | ||
| 748 | assert(optional_header_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ | ||
| 749 | .size = optional_header_size, | ||
| 750 | .alignment = .@"4", | ||
| 751 | .fixed = true, | ||
| 752 | })); | ||
| 753 | coff.nodes.appendAssumeCapacity(.optional_header); | ||
| 754 | if (is_image) switch (magic) { | ||
| 755 | _ => unreachable, | ||
| 756 | .PE32 => { | ||
| 757 | const optional_header: *std.coff.OptionalHeader.PE32 = | ||
| 758 | @ptrCast(@alignCast(optional_header_ni.slice(&coff.mf))); | ||
| 759 | optional_header.* = .{ | ||
| 760 | .standard = .{ | ||
| 761 | .magic = .PE32, | ||
| 762 | .major_linker_version = 0, | ||
| 763 | .minor_linker_version = 0, | ||
| 764 | .size_of_code = 0, | ||
| 765 | .size_of_initialized_data = 0, | ||
| 766 | .size_of_uninitialized_data = 0, | ||
| 767 | .address_of_entry_point = 0, | ||
| 768 | .base_of_code = 0, | ||
| 769 | }, | ||
| 770 | .base_of_data = 0, | ||
| 771 | .image_base = switch (coff.base.comp.config.output_mode) { | ||
| 772 | .Exe => 0x400000, | ||
| 773 | .Lib => switch (coff.base.comp.config.link_mode) { | ||
| 774 | .static => 0, | ||
| 775 | .dynamic => 0x10000000, | ||
| 776 | }, | ||
| 777 | .Obj => 0, | ||
| 778 | }, | ||
| 779 | .section_alignment = @intCast(section_align.toByteUnits()), | ||
| 780 | .file_alignment = @intCast(file_align.toByteUnits()), | ||
| 781 | .major_operating_system_version = 6, | ||
| 782 | .minor_operating_system_version = 0, | ||
| 783 | .major_image_version = 0, | ||
| 784 | .minor_image_version = 0, | ||
| 785 | .major_subsystem_version = major_subsystem_version, | ||
| 786 | .minor_subsystem_version = minor_subsystem_version, | ||
| 787 | .win32_version_value = 0, | ||
| 788 | .size_of_image = 0, | ||
| 789 | .size_of_headers = 0, | ||
| 790 | .checksum = 0, | ||
| 791 | .subsystem = .WINDOWS_CUI, | ||
| 792 | .dll_flags = .{ | ||
| 793 | .HIGH_ENTROPY_VA = true, | ||
| 794 | .DYNAMIC_BASE = true, | ||
| 795 | .TERMINAL_SERVER_AWARE = true, | ||
| 796 | .NX_COMPAT = true, | ||
| 797 | }, | ||
| 798 | .size_of_stack_reserve = default_size_of_stack_reserve, | ||
| 799 | .size_of_stack_commit = default_size_of_stack_commit, | ||
| 800 | .size_of_heap_reserve = default_size_of_heap_reserve, | ||
| 801 | .size_of_heap_commit = default_size_of_heap_commit, | ||
| 802 | .loader_flags = 0, | ||
| 803 | .number_of_rva_and_sizes = data_directories_len, | ||
| 804 | }; | ||
| 805 | if (target_endian != native_endian) | ||
| 806 | std.mem.byteSwapAllFields(std.coff.OptionalHeader.PE32, optional_header); | ||
| 807 | }, | ||
| 808 | .@"PE32+" => { | ||
| 809 | const header: *std.coff.OptionalHeader.@"PE32+" = | ||
| 810 | @ptrCast(@alignCast(optional_header_ni.slice(&coff.mf))); | ||
| 811 | header.* = .{ | ||
| 812 | .standard = .{ | ||
| 813 | .magic = .@"PE32+", | ||
| 814 | .major_linker_version = 0, | ||
| 815 | .minor_linker_version = 0, | ||
| 816 | .size_of_code = 0, | ||
| 817 | .size_of_initialized_data = 0, | ||
| 818 | .size_of_uninitialized_data = 0, | ||
| 819 | .address_of_entry_point = 0, | ||
| 820 | .base_of_code = 0, | ||
| 821 | }, | ||
| 822 | .image_base = switch (coff.base.comp.config.output_mode) { | ||
| 823 | .Exe => 0x140000000, | ||
| 824 | .Lib => switch (coff.base.comp.config.link_mode) { | ||
| 825 | .static => 0, | ||
| 826 | .dynamic => 0x180000000, | ||
| 827 | }, | ||
| 828 | .Obj => 0, | ||
| 829 | }, | ||
| 830 | .section_alignment = @intCast(section_align.toByteUnits()), | ||
| 831 | .file_alignment = @intCast(file_align.toByteUnits()), | ||
| 832 | .major_operating_system_version = 6, | ||
| 833 | .minor_operating_system_version = 0, | ||
| 834 | .major_image_version = 0, | ||
| 835 | .minor_image_version = 0, | ||
| 836 | .major_subsystem_version = major_subsystem_version, | ||
| 837 | .minor_subsystem_version = minor_subsystem_version, | ||
| 838 | .win32_version_value = 0, | ||
| 839 | .size_of_image = 0, | ||
| 840 | .size_of_headers = 0, | ||
| 841 | .checksum = 0, | ||
| 842 | .subsystem = .WINDOWS_CUI, | ||
| 843 | .dll_flags = .{ | ||
| 844 | .HIGH_ENTROPY_VA = true, | ||
| 845 | .DYNAMIC_BASE = true, | ||
| 846 | .TERMINAL_SERVER_AWARE = true, | ||
| 847 | .NX_COMPAT = true, | ||
| 848 | }, | ||
| 849 | .size_of_stack_reserve = default_size_of_stack_reserve, | ||
| 850 | .size_of_stack_commit = default_size_of_stack_commit, | ||
| 851 | .size_of_heap_reserve = default_size_of_heap_reserve, | ||
| 852 | .size_of_heap_commit = default_size_of_heap_commit, | ||
| 853 | .loader_flags = 0, | ||
| 854 | .number_of_rva_and_sizes = data_directories_len, | ||
| 855 | }; | ||
| 856 | if (target_endian != native_endian) | ||
| 857 | std.mem.byteSwapAllFields(std.coff.OptionalHeader.@"PE32+", header); | ||
| 858 | }, | ||
| 859 | }; | ||
| 860 | |||
| 861 | const data_directories_ni = Node.known.data_directories; | ||
| 862 | assert(data_directories_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ | ||
| 863 | .size = data_directories_size, | ||
| 864 | .alignment = .@"4", | ||
| 865 | .fixed = true, | ||
| 866 | })); | ||
| 867 | coff.nodes.appendAssumeCapacity(.data_directories); | ||
| 868 | { | ||
| 869 | const data_directories: *[data_directories_len]std.coff.ImageDataDirectory = | ||
| 870 | @ptrCast(@alignCast(data_directories_ni.slice(&coff.mf))); | ||
| 871 | @memset(data_directories, .{ .virtual_address = 0, .size = 0 }); | ||
| 872 | if (target_endian != native_endian) for (data_directories) |*data_directory| | ||
| 873 | std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, data_directory); | ||
| 874 | } | ||
| 875 | |||
| 876 | const section_table_ni = Node.known.section_table; | ||
| 877 | assert(section_table_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ | ||
| 878 | .alignment = .@"4", | ||
| 879 | .fixed = true, | ||
| 880 | })); | ||
| 881 | coff.nodes.appendAssumeCapacity(.section_table); | ||
| 882 | |||
| 883 | assert(coff.nodes.len == Node.known_count); | ||
| 884 | |||
| 885 | try coff.symbol_table.ensureTotalCapacity(gpa, Symbol.Index.known_count); | ||
| 886 | coff.symbol_table.addOneAssumeCapacity().* = .{ | ||
| 887 | .ni = .none, | ||
| 888 | .rva = 0, | ||
| 889 | .size = 0, | ||
| 890 | .loc_relocs = .none, | ||
| 891 | .target_relocs = .none, | ||
| 892 | .section_number = .UNDEFINED, | ||
| 893 | .data_directory = null, | ||
| 894 | }; | ||
| 895 | assert(try coff.addSection(".data", null, .{ | ||
| 896 | .CNT_INITIALIZED_DATA = true, | ||
| 897 | .MEM_READ = true, | ||
| 898 | .MEM_WRITE = true, | ||
| 899 | }) == .data); | ||
| 900 | assert(try coff.addSection(".idata", .import_table, .{ | ||
| 901 | .CNT_INITIALIZED_DATA = true, | ||
| 902 | .MEM_READ = true, | ||
| 903 | }) == .idata); | ||
| 904 | assert(try coff.addSection(".rdata", null, .{ | ||
| 905 | .CNT_INITIALIZED_DATA = true, | ||
| 906 | .MEM_READ = true, | ||
| 907 | }) == .rdata); | ||
| 908 | assert(try coff.addSection(".text", null, .{ | ||
| 909 | .CNT_CODE = true, | ||
| 910 | .MEM_EXECUTE = true, | ||
| 911 | .MEM_READ = true, | ||
| 912 | }) == .text); | ||
| 913 | coff.import_table.directory_table_ni = try coff.mf.addLastChildNode( | ||
| 914 | gpa, | ||
| 915 | Symbol.Index.idata.node(coff), | ||
| 916 | .{ | ||
| 917 | .alignment = .@"4", | ||
| 918 | .fixed = true, | ||
| 919 | }, | ||
| 920 | ); | ||
| 921 | coff.nodes.appendAssumeCapacity(.import_directory_table); | ||
| 922 | assert(coff.symbol_table.items.len == Symbol.Index.known_count); | ||
| 923 | } | ||
| 924 | |||
| 925 | fn getNode(coff: *const Coff, ni: MappedFile.Node.Index) Node { | ||
| 926 | return coff.nodes.get(@intFromEnum(ni)); | ||
| 927 | } | ||
| 928 | fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 { | ||
| 929 | var section_offset: u32 = 0; | ||
| 930 | var parent_ni = ni; | ||
| 931 | while (true) { | ||
| 932 | assert(parent_ni != .none); | ||
| 933 | switch (coff.getNode(parent_ni)) { | ||
| 934 | else => {}, | ||
| 935 | .section => |si| return si.get(coff).rva + section_offset, | ||
| 936 | } | ||
| 937 | const parent_offset, _ = parent_ni.location(&coff.mf).resolve(&coff.mf); | ||
| 938 | section_offset += @intCast(parent_offset); | ||
| 939 | parent_ni = parent_ni.parent(&coff.mf); | ||
| 940 | } | ||
| 941 | } | ||
| 942 | |||
| 943 | pub inline fn targetEndian(coff: *const Coff) std.builtin.Endian { | ||
| 944 | return coff.endian; | ||
| 945 | } | ||
| 946 | fn targetLoad(coff: *const Coff, ptr: anytype) @typeInfo(@TypeOf(ptr)).pointer.child { | ||
| 947 | const Child = @typeInfo(@TypeOf(ptr)).pointer.child; | ||
| 948 | return switch (@typeInfo(Child)) { | ||
| 949 | else => @compileError(@typeName(Child)), | ||
| 950 | .int => std.mem.toNative(Child, ptr.*, coff.targetEndian()), | ||
| 951 | .@"enum" => |@"enum"| @enumFromInt(coff.targetLoad(@as(*@"enum".tag_type, @ptrCast(ptr)))), | ||
| 952 | .@"struct" => |@"struct"| @bitCast( | ||
| 953 | coff.targetLoad(@as(*@"struct".backing_integer.?, @ptrCast(ptr))), | ||
| 954 | ), | ||
| 955 | }; | ||
| 956 | } | ||
| 957 | fn targetStore(coff: *const Coff, ptr: anytype, val: @typeInfo(@TypeOf(ptr)).pointer.child) void { | ||
| 958 | const Child = @typeInfo(@TypeOf(ptr)).pointer.child; | ||
| 959 | return switch (@typeInfo(Child)) { | ||
| 960 | else => @compileError(@typeName(Child)), | ||
| 961 | .int => ptr.* = std.mem.nativeTo(Child, val, coff.targetEndian()), | ||
| 962 | .@"enum" => |@"enum"| coff.targetStore( | ||
| 963 | @as(*@"enum".tag_type, @ptrCast(ptr)), | ||
| 964 | @intFromEnum(val), | ||
| 965 | ), | ||
| 966 | .@"struct" => |@"struct"| coff.targetStore( | ||
| 967 | @as(*@"struct".backing_integer.?, @ptrCast(ptr)), | ||
| 968 | @bitCast(val), | ||
| 969 | ), | ||
| 970 | }; | ||
| 971 | } | ||
| 972 | |||
| 973 | pub fn headerPtr(coff: *Coff) *std.coff.Header { | ||
| 974 | return @ptrCast(@alignCast(Node.known.coff_header.slice(&coff.mf))); | ||
| 975 | } | ||
| 976 | |||
| 977 | pub fn optionalHeaderStandardPtr(coff: *Coff) *std.coff.OptionalHeader { | ||
| 978 | return @ptrCast(@alignCast( | ||
| 979 | Node.known.optional_header.slice(&coff.mf)[0..@sizeOf(std.coff.OptionalHeader)], | ||
| 980 | )); | ||
| 981 | } | ||
| 982 | |||
| 983 | pub const OptionalHeaderPtr = union(std.coff.OptionalHeader.Magic) { | ||
| 984 | PE32: *std.coff.OptionalHeader.PE32, | ||
| 985 | @"PE32+": *std.coff.OptionalHeader.@"PE32+", | ||
| 986 | }; | ||
| 987 | pub fn optionalHeaderPtr(coff: *Coff) OptionalHeaderPtr { | ||
| 988 | const slice = Node.known.optional_header.slice(&coff.mf); | ||
| 989 | return switch (coff.targetLoad(&coff.optionalHeaderStandardPtr().magic)) { | ||
| 990 | _ => unreachable, | ||
| 991 | inline else => |magic| @unionInit( | ||
| 992 | OptionalHeaderPtr, | ||
| 993 | @tagName(magic), | ||
| 994 | @ptrCast(@alignCast(slice)), | ||
| 995 | ), | ||
| 996 | }; | ||
| 997 | } | ||
| 998 | pub fn optionalHeaderField( | ||
| 999 | coff: *Coff, | ||
| 1000 | comptime field: std.meta.FieldEnum(std.coff.OptionalHeader.@"PE32+"), | ||
| 1001 | ) @FieldType(std.coff.OptionalHeader.@"PE32+", @tagName(field)) { | ||
| 1002 | return switch (coff.optionalHeaderPtr()) { | ||
| 1003 | inline else => |optional_header| coff.targetLoad(&@field(optional_header, @tagName(field))), | ||
| 1004 | }; | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | pub fn dataDirectoriesSlice(coff: *Coff) []std.coff.ImageDataDirectory { | ||
| 1008 | return @ptrCast(@alignCast(Node.known.data_directories.slice(&coff.mf))); | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | pub fn sectionTableSlice(coff: *Coff) []std.coff.SectionHeader { | ||
| 1012 | return @ptrCast(@alignCast(Node.known.section_table.slice(&coff.mf))); | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index { | ||
| 1016 | defer coff.symbol_table.addOneAssumeCapacity().* = .{ | ||
| 1017 | .ni = .none, | ||
| 1018 | .rva = 0, | ||
| 1019 | .size = 0, | ||
| 1020 | .loc_relocs = .none, | ||
| 1021 | .target_relocs = .none, | ||
| 1022 | .section_number = .UNDEFINED, | ||
| 1023 | .data_directory = null, | ||
| 1024 | }; | ||
| 1025 | return @enumFromInt(coff.symbol_table.items.len); | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | fn initSymbolAssumeCapacity(coff: *Coff) !Symbol.Index { | ||
| 1029 | const si = coff.addSymbolAssumeCapacity(); | ||
| 1030 | return si; | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | fn getOrPutString(coff: *Coff, string: []const u8) !String { | ||
| 1034 | const gpa = coff.base.comp.gpa; | ||
| 1035 | try coff.string_bytes.ensureUnusedCapacity(gpa, string.len + 1); | ||
| 1036 | const gop = try coff.strings.getOrPutContextAdapted( | ||
| 1037 | gpa, | ||
| 1038 | string, | ||
| 1039 | std.hash_map.StringIndexAdapter{ .bytes = &coff.string_bytes }, | ||
| 1040 | .{ .bytes = &coff.string_bytes }, | ||
| 1041 | ); | ||
| 1042 | if (!gop.found_existing) { | ||
| 1043 | gop.key_ptr.* = @intCast(coff.string_bytes.items.len); | ||
| 1044 | gop.value_ptr.* = {}; | ||
| 1045 | coff.string_bytes.appendSliceAssumeCapacity(string); | ||
| 1046 | coff.string_bytes.appendAssumeCapacity(0); | ||
| 1047 | } | ||
| 1048 | return @enumFromInt(gop.key_ptr.*); | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | fn getOrPutOptionalString(coff: *Coff, string: ?[]const u8) !String.Optional { | ||
| 1052 | return (try coff.getOrPutString(string orelse return .none)).toOptional(); | ||
| 1053 | } | ||
| 1054 | |||
| 1055 | pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbol.Index { | ||
| 1056 | const gpa = coff.base.comp.gpa; | ||
| 1057 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | ||
| 1058 | const sym_gop = try coff.globals.getOrPut(gpa, .{ | ||
| 1059 | .name = try coff.getOrPutString(name), | ||
| 1060 | .lib_name = try coff.getOrPutOptionalString(lib_name), | ||
| 1061 | }); | ||
| 1062 | if (!sym_gop.found_existing) { | ||
| 1063 | sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity(); | ||
| 1064 | coff.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1); | ||
| 1065 | } | ||
| 1066 | return sym_gop.value_ptr.*; | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | fn navMapIndex(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex { | ||
| 1070 | const gpa = zcu.gpa; | ||
| 1071 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | ||
| 1072 | const sym_gop = try coff.navs.getOrPut(gpa, nav_index); | ||
| 1073 | if (!sym_gop.found_existing) sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity(); | ||
| 1074 | return @enumFromInt(sym_gop.index); | ||
| 1075 | } | ||
| 1076 | pub fn navSymbol(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index { | ||
| 1077 | const ip = &zcu.intern_pool; | ||
| 1078 | const nav = ip.getNav(nav_index); | ||
| 1079 | if (nav.getExtern(ip)) |@"extern"| return coff.globalSymbol( | ||
| 1080 | @"extern".name.toSlice(ip), | ||
| 1081 | @"extern".lib_name.toSlice(ip), | ||
| 1082 | ); | ||
| 1083 | const nmi = try coff.navMapIndex(zcu, nav_index); | ||
| 1084 | return nmi.symbol(coff); | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | fn uavMapIndex(coff: *Coff, uav_val: InternPool.Index) !Node.UavMapIndex { | ||
| 1088 | const gpa = coff.base.comp.gpa; | ||
| 1089 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | ||
| 1090 | const sym_gop = try coff.uavs.getOrPut(gpa, uav_val); | ||
| 1091 | if (!sym_gop.found_existing) sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity(); | ||
| 1092 | return @enumFromInt(sym_gop.index); | ||
| 1093 | } | ||
| 1094 | pub fn uavSymbol(coff: *Coff, uav_val: InternPool.Index) !Symbol.Index { | ||
| 1095 | const umi = try coff.uavMapIndex(uav_val); | ||
| 1096 | return umi.symbol(coff); | ||
| 1097 | } | ||
| 1098 | |||
| 1099 | pub fn lazySymbol(coff: *Coff, lazy: link.File.LazySymbol) !Symbol.Index { | ||
| 1100 | const gpa = coff.base.comp.gpa; | ||
| 1101 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | ||
| 1102 | const sym_gop = try coff.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty); | ||
| 1103 | if (!sym_gop.found_existing) { | ||
| 1104 | sym_gop.value_ptr.* = try coff.initSymbolAssumeCapacity(); | ||
| 1105 | coff.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1); | ||
| 1106 | } | ||
| 1107 | return sym_gop.value_ptr.*; | ||
| 1108 | } | ||
| 1109 | |||
| 1110 | pub fn getNavVAddr( | ||
| 1111 | coff: *Coff, | ||
| 1112 | pt: Zcu.PerThread, | ||
| 1113 | nav: InternPool.Nav.Index, | ||
| 1114 | reloc_info: link.File.RelocInfo, | ||
| 1115 | ) !u64 { | ||
| 1116 | return coff.getVAddr(reloc_info, try coff.navSymbol(pt.zcu, nav)); | ||
| 1117 | } | ||
| 1118 | |||
| 1119 | pub fn getUavVAddr( | ||
| 1120 | coff: *Coff, | ||
| 1121 | uav: InternPool.Index, | ||
| 1122 | reloc_info: link.File.RelocInfo, | ||
| 1123 | ) !u64 { | ||
| 1124 | return coff.getVAddr(reloc_info, try coff.uavSymbol(uav)); | ||
| 1125 | } | ||
| 1126 | |||
| 1127 | pub fn getVAddr(coff: *Coff, reloc_info: link.File.RelocInfo, target_si: Symbol.Index) !u64 { | ||
| 1128 | try coff.addReloc( | ||
| 1129 | @enumFromInt(reloc_info.parent.atom_index), | ||
| 1130 | reloc_info.offset, | ||
| 1131 | target_si, | ||
| 1132 | reloc_info.addend, | ||
| 1133 | switch (coff.targetLoad(&coff.headerPtr().machine)) { | ||
| 1134 | else => unreachable, | ||
| 1135 | .AMD64 => .{ .AMD64 = .ADDR64 }, | ||
| 1136 | .I386 => .{ .I386 = .DIR32 }, | ||
| 1137 | }, | ||
| 1138 | ); | ||
| 1139 | return coff.optionalHeaderField(.image_base) + target_si.get(coff).rva; | ||
| 1140 | } | ||
| 1141 | |||
| 1142 | fn addSection( | ||
| 1143 | coff: *Coff, | ||
| 1144 | name: []const u8, | ||
| 1145 | maybe_data_directory: ?DataDirectory, | ||
| 1146 | flags: std.coff.SectionHeader.Flags, | ||
| 1147 | ) !Symbol.Index { | ||
| 1148 | const gpa = coff.base.comp.gpa; | ||
| 1149 | try coff.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 1150 | try coff.section_table.ensureUnusedCapacity(gpa, 1); | ||
| 1151 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | ||
| 1152 | |||
| 1153 | const coff_header = coff.headerPtr(); | ||
| 1154 | const section_index = coff.targetLoad(&coff_header.number_of_sections); | ||
| 1155 | const section_table_len = section_index + 1; | ||
| 1156 | coff.targetStore(&coff_header.number_of_sections, section_table_len); | ||
| 1157 | try Node.known.section_table.resize( | ||
| 1158 | &coff.mf, | ||
| 1159 | gpa, | ||
| 1160 | @sizeOf(std.coff.SectionHeader) * section_table_len, | ||
| 1161 | ); | ||
| 1162 | const ni = try coff.mf.addLastChildNode(gpa, .root, .{ | ||
| 1163 | .alignment = coff.mf.flags.block_size, | ||
| 1164 | .moved = true, | ||
| 1165 | .bubbles_moved = false, | ||
| 1166 | }); | ||
| 1167 | const si = coff.addSymbolAssumeCapacity(); | ||
| 1168 | coff.section_table.appendAssumeCapacity(si); | ||
| 1169 | coff.nodes.appendAssumeCapacity(.{ .section = si }); | ||
| 1170 | const section_table = coff.sectionTableSlice(); | ||
| 1171 | const virtual_size = coff.optionalHeaderField(.section_alignment); | ||
| 1172 | const rva: u32 = switch (section_index) { | ||
| 1173 | 0 => @intCast(Node.known.header.location(&coff.mf).resolve(&coff.mf)[1]), | ||
| 1174 | else => coff.section_table.items[section_index - 1].get(coff).rva + | ||
| 1175 | coff.targetLoad(&section_table[section_index - 1].virtual_size), | ||
| 1176 | }; | ||
| 1177 | { | ||
| 1178 | const sym = si.get(coff); | ||
| 1179 | sym.ni = ni; | ||
| 1180 | sym.rva = rva; | ||
| 1181 | sym.section_number = @enumFromInt(section_table_len); | ||
| 1182 | sym.data_directory = maybe_data_directory; | ||
| 1183 | } | ||
| 1184 | const section = &section_table[section_index]; | ||
| 1185 | section.* = .{ | ||
| 1186 | .name = undefined, | ||
| 1187 | .virtual_size = virtual_size, | ||
| 1188 | .virtual_address = rva, | ||
| 1189 | .size_of_raw_data = 0, | ||
| 1190 | .pointer_to_raw_data = 0, | ||
| 1191 | .pointer_to_relocations = 0, | ||
| 1192 | .pointer_to_linenumbers = 0, | ||
| 1193 | .number_of_relocations = 0, | ||
| 1194 | .number_of_linenumbers = 0, | ||
| 1195 | .flags = flags, | ||
| 1196 | }; | ||
| 1197 | @memcpy(section.name[0..name.len], name); | ||
| 1198 | @memset(section.name[name.len..], 0); | ||
| 1199 | if (coff.targetEndian() != native_endian) | ||
| 1200 | std.mem.byteSwapAllFields(std.coff.SectionHeader, section); | ||
| 1201 | if (maybe_data_directory) |data_directory| | ||
| 1202 | coff.dataDirectoriesSlice()[@intFromEnum(data_directory)] = .{ | ||
| 1203 | .virtual_address = section.virtual_address, | ||
| 1204 | .size = section.virtual_size, | ||
| 1205 | }; | ||
| 1206 | switch (coff.optionalHeaderPtr()) { | ||
| 1207 | inline else => |optional_header| coff.targetStore( | ||
| 1208 | &optional_header.size_of_image, | ||
| 1209 | @intCast(rva + virtual_size), | ||
| 1210 | ), | ||
| 1211 | } | ||
| 1212 | return si; | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | pub fn addReloc( | ||
| 1216 | coff: *Coff, | ||
| 1217 | loc_si: Symbol.Index, | ||
| 1218 | offset: u64, | ||
| 1219 | target_si: Symbol.Index, | ||
| 1220 | addend: i64, | ||
| 1221 | @"type": Reloc.Type, | ||
| 1222 | ) !void { | ||
| 1223 | const gpa = coff.base.comp.gpa; | ||
| 1224 | const target = target_si.get(coff); | ||
| 1225 | const ri: Reloc.Index = @enumFromInt(coff.relocs.items.len); | ||
| 1226 | (try coff.relocs.addOne(gpa)).* = .{ | ||
| 1227 | .type = @"type", | ||
| 1228 | .prev = .none, | ||
| 1229 | .next = target.target_relocs, | ||
| 1230 | .loc = loc_si, | ||
| 1231 | .target = target_si, | ||
| 1232 | .unused = 0, | ||
| 1233 | .offset = offset, | ||
| 1234 | .addend = addend, | ||
| 1235 | }; | ||
| 1236 | switch (target.target_relocs) { | ||
| 1237 | .none => {}, | ||
| 1238 | else => |target_ri| target_ri.get(coff).prev = ri, | ||
| 1239 | } | ||
| 1240 | target.target_relocs = ri; | ||
| 1241 | } | ||
| 1242 | |||
| 1243 | pub fn prelink(coff: *Coff, prog_node: std.Progress.Node) void { | ||
| 1244 | _ = coff; | ||
| 1245 | _ = prog_node; | ||
| 1246 | } | ||
| 1247 | |||
| 1248 | pub fn updateNav(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { | ||
| 1249 | coff.updateNavInner(pt, nav_index) catch |err| switch (err) { | ||
| 1250 | error.OutOfMemory, | ||
| 1251 | error.Overflow, | ||
| 1252 | error.RelocationNotByteAligned, | ||
| 1253 | => |e| return e, | ||
| 1254 | else => |e| return coff.base.cgFail(nav_index, "linker failed to update variable: {t}", .{e}), | ||
| 1255 | }; | ||
| 1256 | } | ||
| 1257 | fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { | ||
| 1258 | const zcu = pt.zcu; | ||
| 1259 | const gpa = zcu.gpa; | ||
| 1260 | const ip = &zcu.intern_pool; | ||
| 1261 | |||
| 1262 | const nav = ip.getNav(nav_index); | ||
| 1263 | const nav_val = nav.status.fully_resolved.val; | ||
| 1264 | const nav_init, const is_threadlocal = switch (ip.indexToKey(nav_val)) { | ||
| 1265 | else => .{ nav_val, false }, | ||
| 1266 | .variable => |variable| .{ variable.init, variable.is_threadlocal }, | ||
| 1267 | .@"extern" => return, | ||
| 1268 | .func => .{ .none, false }, | ||
| 1269 | }; | ||
| 1270 | if (nav_init == .none or !Type.fromInterned(ip.typeOf(nav_init)).hasRuntimeBits(zcu)) return; | ||
| 1271 | |||
| 1272 | const nmi = try coff.navMapIndex(zcu, nav_index); | ||
| 1273 | const si = nmi.symbol(coff); | ||
| 1274 | const ni = ni: { | ||
| 1275 | const sym = si.get(coff); | ||
| 1276 | switch (sym.ni) { | ||
| 1277 | .none => { | ||
| 1278 | try coff.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 1279 | _ = is_threadlocal; | ||
| 1280 | const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.data.node(coff), .{ | ||
| 1281 | .alignment = pt.navAlignment(nav_index).toStdMem(), | ||
| 1282 | .moved = true, | ||
| 1283 | }); | ||
| 1284 | coff.nodes.appendAssumeCapacity(.{ .nav = nmi }); | ||
| 1285 | sym.ni = ni; | ||
| 1286 | sym.section_number = Symbol.Index.data.get(coff).section_number; | ||
| 1287 | }, | ||
| 1288 | else => si.deleteLocationRelocs(coff), | ||
| 1289 | } | ||
| 1290 | assert(sym.loc_relocs == .none); | ||
| 1291 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | ||
| 1292 | break :ni sym.ni; | ||
| 1293 | }; | ||
| 1294 | |||
| 1295 | var nw: MappedFile.Node.Writer = undefined; | ||
| 1296 | ni.writer(&coff.mf, gpa, &nw); | ||
| 1297 | defer nw.deinit(); | ||
| 1298 | codegen.generateSymbol( | ||
| 1299 | &coff.base, | ||
| 1300 | pt, | ||
| 1301 | zcu.navSrcLoc(nav_index), | ||
| 1302 | .fromInterned(nav_init), | ||
| 1303 | &nw.interface, | ||
| 1304 | .{ .atom_index = @intFromEnum(si) }, | ||
| 1305 | ) catch |err| switch (err) { | ||
| 1306 | error.WriteFailed => return error.OutOfMemory, | ||
| 1307 | else => |e| return e, | ||
| 1308 | }; | ||
| 1309 | si.get(coff).size = @intCast(nw.interface.end); | ||
| 1310 | si.applyLocationRelocs(coff); | ||
| 1311 | } | ||
| 1312 | |||
| 1313 | pub fn lowerUav( | ||
| 1314 | coff: *Coff, | ||
| 1315 | pt: Zcu.PerThread, | ||
| 1316 | uav_val: InternPool.Index, | ||
| 1317 | uav_align: InternPool.Alignment, | ||
| 1318 | src_loc: Zcu.LazySrcLoc, | ||
| 1319 | ) !codegen.SymbolResult { | ||
| 1320 | const zcu = pt.zcu; | ||
| 1321 | const gpa = zcu.gpa; | ||
| 1322 | |||
| 1323 | try coff.pending_uavs.ensureUnusedCapacity(gpa, 1); | ||
| 1324 | const umi = try coff.uavMapIndex(uav_val); | ||
| 1325 | const si = umi.symbol(coff); | ||
| 1326 | if (switch (si.get(coff).ni) { | ||
| 1327 | .none => true, | ||
| 1328 | else => |ni| uav_align.toStdMem().order(ni.alignment(&coff.mf)).compare(.gt), | ||
| 1329 | }) { | ||
| 1330 | const gop = coff.pending_uavs.getOrPutAssumeCapacity(umi); | ||
| 1331 | if (gop.found_existing) { | ||
| 1332 | gop.value_ptr.alignment = gop.value_ptr.alignment.max(uav_align); | ||
| 1333 | } else { | ||
| 1334 | gop.value_ptr.* = .{ | ||
| 1335 | .alignment = uav_align, | ||
| 1336 | .src_loc = src_loc, | ||
| 1337 | }; | ||
| 1338 | coff.base.comp.link_const_prog_node.increaseEstimatedTotalItems(1); | ||
| 1339 | } | ||
| 1340 | } | ||
| 1341 | return .{ .sym_index = @intFromEnum(si) }; | ||
| 1342 | } | ||
| 1343 | |||
| 1344 | pub fn updateFunc( | ||
| 1345 | coff: *Coff, | ||
| 1346 | pt: Zcu.PerThread, | ||
| 1347 | func_index: InternPool.Index, | ||
| 1348 | mir: *const codegen.AnyMir, | ||
| 1349 | ) !void { | ||
| 1350 | coff.updateFuncInner(pt, func_index, mir) catch |err| switch (err) { | ||
| 1351 | error.OutOfMemory, | ||
| 1352 | error.Overflow, | ||
| 1353 | error.RelocationNotByteAligned, | ||
| 1354 | error.CodegenFail, | ||
| 1355 | => |e| return e, | ||
| 1356 | else => |e| return coff.base.cgFail( | ||
| 1357 | pt.zcu.funcInfo(func_index).owner_nav, | ||
| 1358 | "linker failed to update function: {s}", | ||
| 1359 | .{@errorName(e)}, | ||
| 1360 | ), | ||
| 1361 | }; | ||
| 1362 | } | ||
| 1363 | fn updateFuncInner( | ||
| 1364 | coff: *Coff, | ||
| 1365 | pt: Zcu.PerThread, | ||
| 1366 | func_index: InternPool.Index, | ||
| 1367 | mir: *const codegen.AnyMir, | ||
| 1368 | ) !void { | ||
| 1369 | const zcu = pt.zcu; | ||
| 1370 | const gpa = zcu.gpa; | ||
| 1371 | const ip = &zcu.intern_pool; | ||
| 1372 | const func = zcu.funcInfo(func_index); | ||
| 1373 | const nav = ip.getNav(func.owner_nav); | ||
| 1374 | |||
| 1375 | const nmi = try coff.navMapIndex(zcu, func.owner_nav); | ||
| 1376 | const si = nmi.symbol(coff); | ||
| 1377 | log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), si }); | ||
| 1378 | const ni = ni: { | ||
| 1379 | const sym = si.get(coff); | ||
| 1380 | switch (sym.ni) { | ||
| 1381 | .none => { | ||
| 1382 | try coff.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 1383 | const mod = zcu.navFileScope(func.owner_nav).mod.?; | ||
| 1384 | const target = &mod.resolved_target.result; | ||
| 1385 | const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.text.node(coff), .{ | ||
| 1386 | .alignment = switch (nav.status.fully_resolved.alignment) { | ||
| 1387 | .none => switch (mod.optimize_mode) { | ||
| 1388 | .Debug, | ||
| 1389 | .ReleaseSafe, | ||
| 1390 | .ReleaseFast, | ||
| 1391 | => target_util.defaultFunctionAlignment(target), | ||
| 1392 | .ReleaseSmall => target_util.minFunctionAlignment(target), | ||
| 1393 | }, | ||
| 1394 | else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), | ||
| 1395 | }.toStdMem(), | ||
| 1396 | .moved = true, | ||
| 1397 | }); | ||
| 1398 | coff.nodes.appendAssumeCapacity(.{ .nav = nmi }); | ||
| 1399 | sym.ni = ni; | ||
| 1400 | sym.section_number = Symbol.Index.text.get(coff).section_number; | ||
| 1401 | }, | ||
| 1402 | else => si.deleteLocationRelocs(coff), | ||
| 1403 | } | ||
| 1404 | assert(sym.loc_relocs == .none); | ||
| 1405 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | ||
| 1406 | break :ni sym.ni; | ||
| 1407 | }; | ||
| 1408 | |||
| 1409 | var nw: MappedFile.Node.Writer = undefined; | ||
| 1410 | ni.writer(&coff.mf, gpa, &nw); | ||
| 1411 | defer nw.deinit(); | ||
| 1412 | codegen.emitFunction( | ||
| 1413 | &coff.base, | ||
| 1414 | pt, | ||
| 1415 | zcu.navSrcLoc(func.owner_nav), | ||
| 1416 | func_index, | ||
| 1417 | @intFromEnum(si), | ||
| 1418 | mir, | ||
| 1419 | &nw.interface, | ||
| 1420 | .none, | ||
| 1421 | ) catch |err| switch (err) { | ||
| 1422 | error.WriteFailed => return nw.err.?, | ||
| 1423 | else => |e| return e, | ||
| 1424 | }; | ||
| 1425 | si.get(coff).size = @intCast(nw.interface.end); | ||
| 1426 | si.applyLocationRelocs(coff); | ||
| 1427 | } | ||
| 1428 | |||
| 1429 | pub fn updateErrorData(coff: *Coff, pt: Zcu.PerThread) !void { | ||
| 1430 | coff.flushLazy(pt, .{ | ||
| 1431 | .kind = .const_data, | ||
| 1432 | .index = @intCast(coff.lazy.getPtr(.const_data).map.getIndex(.anyerror_type) orelse return), | ||
| 1433 | }) catch |err| switch (err) { | ||
| 1434 | error.OutOfMemory => return error.OutOfMemory, | ||
| 1435 | error.CodegenFail => return error.LinkFailure, | ||
| 1436 | else => |e| return coff.base.comp.link_diags.fail("updateErrorData failed {t}", .{e}), | ||
| 1437 | }; | ||
| 1438 | } | ||
| 1439 | |||
| 1440 | pub fn flush( | ||
| 1441 | coff: *Coff, | ||
| 1442 | arena: std.mem.Allocator, | ||
| 1443 | tid: Zcu.PerThread.Id, | ||
| 1444 | prog_node: std.Progress.Node, | ||
| 1445 | ) !void { | ||
| 1446 | _ = arena; | ||
| 1447 | _ = prog_node; | ||
| 1448 | while (try coff.idle(tid)) {} | ||
| 1449 | |||
| 1450 | // hack for stage2_x86_64 + coff | ||
| 1451 | const comp = coff.base.comp; | ||
| 1452 | if (comp.compiler_rt_dyn_lib) |crt_file| { | ||
| 1453 | const gpa = comp.gpa; | ||
| 1454 | const compiler_rt_sub_path = try std.fs.path.join(gpa, &.{ | ||
| 1455 | std.fs.path.dirname(coff.base.emit.sub_path) orelse "", | ||
| 1456 | std.fs.path.basename(crt_file.full_object_path.sub_path), | ||
| 1457 | }); | ||
| 1458 | defer gpa.free(compiler_rt_sub_path); | ||
| 1459 | crt_file.full_object_path.root_dir.handle.copyFile( | ||
| 1460 | crt_file.full_object_path.sub_path, | ||
| 1461 | coff.base.emit.root_dir.handle, | ||
| 1462 | compiler_rt_sub_path, | ||
| 1463 | .{}, | ||
| 1464 | ) catch |err| switch (err) { | ||
| 1465 | else => |e| return comp.link_diags.fail("Copy '{s}' failed: {s}", .{ | ||
| 1466 | compiler_rt_sub_path, | ||
| 1467 | @errorName(e), | ||
| 1468 | }), | ||
| 1469 | }; | ||
| 1470 | } | ||
| 1471 | } | ||
| 1472 | |||
| 1473 | pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { | ||
| 1474 | const comp = coff.base.comp; | ||
| 1475 | task: { | ||
| 1476 | while (coff.pending_uavs.pop()) |pending_uav| { | ||
| 1477 | const sub_prog_node = coff.idleProgNode( | ||
| 1478 | tid, | ||
| 1479 | comp.link_const_prog_node, | ||
| 1480 | .{ .uav = pending_uav.key }, | ||
| 1481 | ); | ||
| 1482 | defer sub_prog_node.end(); | ||
| 1483 | coff.flushUav( | ||
| 1484 | .{ .zcu = coff.base.comp.zcu.?, .tid = tid }, | ||
| 1485 | pending_uav.key, | ||
| 1486 | pending_uav.value.alignment, | ||
| 1487 | pending_uav.value.src_loc, | ||
| 1488 | ) catch |err| switch (err) { | ||
| 1489 | error.OutOfMemory => return error.OutOfMemory, | ||
| 1490 | else => |e| return coff.base.comp.link_diags.fail( | ||
| 1491 | "linker failed to lower constant: {t}", | ||
| 1492 | .{e}, | ||
| 1493 | ), | ||
| 1494 | }; | ||
| 1495 | break :task; | ||
| 1496 | } | ||
| 1497 | if (coff.global_pending_index < coff.globals.count()) { | ||
| 1498 | const pt: Zcu.PerThread = .{ .zcu = coff.base.comp.zcu.?, .tid = tid }; | ||
| 1499 | const gmi: Node.GlobalMapIndex = @enumFromInt(coff.global_pending_index); | ||
| 1500 | coff.global_pending_index += 1; | ||
| 1501 | const sub_prog_node = comp.link_synth_prog_node.start( | ||
| 1502 | gmi.globalName(coff).name.toSlice(coff), | ||
| 1503 | 0, | ||
| 1504 | ); | ||
| 1505 | defer sub_prog_node.end(); | ||
| 1506 | coff.flushGlobal(pt, gmi) catch |err| switch (err) { | ||
| 1507 | error.OutOfMemory => return error.OutOfMemory, | ||
| 1508 | else => |e| return coff.base.comp.link_diags.fail( | ||
| 1509 | "linker failed to lower constant: {t}", | ||
| 1510 | .{e}, | ||
| 1511 | ), | ||
| 1512 | }; | ||
| 1513 | break :task; | ||
| 1514 | } | ||
| 1515 | var lazy_it = coff.lazy.iterator(); | ||
| 1516 | while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) { | ||
| 1517 | const pt: Zcu.PerThread = .{ .zcu = coff.base.comp.zcu.?, .tid = tid }; | ||
| 1518 | const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index }; | ||
| 1519 | lazy.value.pending_index += 1; | ||
| 1520 | const kind = switch (lmr.kind) { | ||
| 1521 | .code => "code", | ||
| 1522 | .const_data => "data", | ||
| 1523 | }; | ||
| 1524 | var name: [std.Progress.Node.max_name_len]u8 = undefined; | ||
| 1525 | const sub_prog_node = comp.link_synth_prog_node.start( | ||
| 1526 | std.fmt.bufPrint(&name, "lazy {s} for {f}", .{ | ||
| 1527 | kind, | ||
| 1528 | Type.fromInterned(lmr.lazySymbol(coff).ty).fmt(pt), | ||
| 1529 | }) catch &name, | ||
| 1530 | 0, | ||
| 1531 | ); | ||
| 1532 | defer sub_prog_node.end(); | ||
| 1533 | coff.flushLazy(pt, lmr) catch |err| switch (err) { | ||
| 1534 | error.OutOfMemory => return error.OutOfMemory, | ||
| 1535 | else => |e| return coff.base.comp.link_diags.fail( | ||
| 1536 | "linker failed to lower lazy {s}: {t}", | ||
| 1537 | .{ kind, e }, | ||
| 1538 | ), | ||
| 1539 | }; | ||
| 1540 | break :task; | ||
| 1541 | }; | ||
| 1542 | while (coff.mf.updates.pop()) |ni| { | ||
| 1543 | const clean_moved = ni.cleanMoved(&coff.mf); | ||
| 1544 | const clean_resized = ni.cleanResized(&coff.mf); | ||
| 1545 | if (clean_moved or clean_resized) { | ||
| 1546 | const sub_prog_node = coff.idleProgNode(tid, coff.mf.update_prog_node, coff.getNode(ni)); | ||
| 1547 | defer sub_prog_node.end(); | ||
| 1548 | if (clean_moved) try coff.flushMoved(ni); | ||
| 1549 | if (clean_resized) try coff.flushResized(ni); | ||
| 1550 | break :task; | ||
| 1551 | } else coff.mf.update_prog_node.completeOne(); | ||
| 1552 | } | ||
| 1553 | } | ||
| 1554 | if (coff.pending_uavs.count() > 0) return true; | ||
| 1555 | for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; | ||
| 1556 | if (coff.mf.updates.items.len > 0) return true; | ||
| 1557 | return false; | ||
| 1558 | } | ||
| 1559 | |||
| 1560 | fn idleProgNode( | ||
| 1561 | coff: *Coff, | ||
| 1562 | tid: Zcu.PerThread.Id, | ||
| 1563 | prog_node: std.Progress.Node, | ||
| 1564 | node: Node, | ||
| 1565 | ) std.Progress.Node { | ||
| 1566 | var name: [std.Progress.Node.max_name_len]u8 = undefined; | ||
| 1567 | return prog_node.start(name: switch (node) { | ||
| 1568 | else => |tag| @tagName(tag), | ||
| 1569 | .section => |si| std.mem.sliceTo(&si.get(coff).section_number.header(coff).name, 0), | ||
| 1570 | .nav => |nmi| { | ||
| 1571 | const ip = &coff.base.comp.zcu.?.intern_pool; | ||
| 1572 | break :name ip.getNav(nmi.navIndex(coff)).fqn.toSlice(ip); | ||
| 1573 | }, | ||
| 1574 | .uav => |umi| std.fmt.bufPrint(&name, "{f}", .{ | ||
| 1575 | Value.fromInterned(umi.uavValue(coff)).fmtValue(.{ | ||
| 1576 | .zcu = coff.base.comp.zcu.?, | ||
| 1577 | .tid = tid, | ||
| 1578 | }), | ||
| 1579 | }) catch &name, | ||
| 1580 | }, 0); | ||
| 1581 | } | ||
| 1582 | |||
| 1583 | fn flushUav( | ||
| 1584 | coff: *Coff, | ||
| 1585 | pt: Zcu.PerThread, | ||
| 1586 | umi: Node.UavMapIndex, | ||
| 1587 | uav_align: InternPool.Alignment, | ||
| 1588 | src_loc: Zcu.LazySrcLoc, | ||
| 1589 | ) !void { | ||
| 1590 | const zcu = pt.zcu; | ||
| 1591 | const gpa = zcu.gpa; | ||
| 1592 | |||
| 1593 | const uav_val = umi.uavValue(coff); | ||
| 1594 | const si = umi.symbol(coff); | ||
| 1595 | const ni = ni: { | ||
| 1596 | const sym = si.get(coff); | ||
| 1597 | switch (sym.ni) { | ||
| 1598 | .none => { | ||
| 1599 | try coff.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 1600 | const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.data.node(coff), .{ | ||
| 1601 | .alignment = uav_align.toStdMem(), | ||
| 1602 | .moved = true, | ||
| 1603 | }); | ||
| 1604 | coff.nodes.appendAssumeCapacity(.{ .uav = umi }); | ||
| 1605 | sym.ni = ni; | ||
| 1606 | sym.section_number = Symbol.Index.data.get(coff).section_number; | ||
| 1607 | }, | ||
| 1608 | else => { | ||
| 1609 | if (sym.ni.alignment(&coff.mf).order(uav_align.toStdMem()).compare(.gte)) return; | ||
| 1610 | si.deleteLocationRelocs(coff); | ||
| 1611 | }, | ||
| 1612 | } | ||
| 1613 | assert(sym.loc_relocs == .none); | ||
| 1614 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | ||
| 1615 | break :ni sym.ni; | ||
| 1616 | }; | ||
| 1617 | |||
| 1618 | var nw: MappedFile.Node.Writer = undefined; | ||
| 1619 | ni.writer(&coff.mf, gpa, &nw); | ||
| 1620 | defer nw.deinit(); | ||
| 1621 | codegen.generateSymbol( | ||
| 1622 | &coff.base, | ||
| 1623 | pt, | ||
| 1624 | src_loc, | ||
| 1625 | .fromInterned(uav_val), | ||
| 1626 | &nw.interface, | ||
| 1627 | .{ .atom_index = @intFromEnum(si) }, | ||
| 1628 | ) catch |err| switch (err) { | ||
| 1629 | error.WriteFailed => return error.OutOfMemory, | ||
| 1630 | else => |e| return e, | ||
| 1631 | }; | ||
| 1632 | si.get(coff).size = @intCast(nw.interface.end); | ||
| 1633 | si.applyLocationRelocs(coff); | ||
| 1634 | } | ||
| 1635 | |||
| 1636 | fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void { | ||
| 1637 | const zcu = pt.zcu; | ||
| 1638 | const comp = zcu.comp; | ||
| 1639 | const gpa = zcu.gpa; | ||
| 1640 | const gn = gmi.globalName(coff); | ||
| 1641 | if (gn.lib_name.toSlice(coff)) |lib_name| { | ||
| 1642 | const name = gn.name.toSlice(coff); | ||
| 1643 | try coff.nodes.ensureUnusedCapacity(gpa, 4); | ||
| 1644 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | ||
| 1645 | |||
| 1646 | const target_endian = coff.targetEndian(); | ||
| 1647 | const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic); | ||
| 1648 | const addr_size: u64, const addr_align: std.mem.Alignment = switch (magic) { | ||
| 1649 | _ => unreachable, | ||
| 1650 | .PE32 => .{ 4, .@"4" }, | ||
| 1651 | .@"PE32+" => .{ 8, .@"8" }, | ||
| 1652 | }; | ||
| 1653 | |||
| 1654 | const gop = try coff.import_table.dlls.getOrPutAdapted( | ||
| 1655 | gpa, | ||
| 1656 | lib_name, | ||
| 1657 | ImportTable.Adapter{ .coff = coff }, | ||
| 1658 | ); | ||
| 1659 | const import_hint_name_align: std.mem.Alignment = .@"2"; | ||
| 1660 | if (!gop.found_existing) { | ||
| 1661 | errdefer _ = coff.import_table.dlls.pop(); | ||
| 1662 | try coff.import_table.directory_table_ni.resize( | ||
| 1663 | &coff.mf, | ||
| 1664 | gpa, | ||
| 1665 | @sizeOf(std.coff.ImportDirectoryEntry) * (gop.index + 2), | ||
| 1666 | ); | ||
| 1667 | const import_hint_name_table_len = | ||
| 1668 | import_hint_name_align.forward(lib_name.len + ".dll".len + 1); | ||
| 1669 | const idata_section_ni = Symbol.Index.idata.node(coff); | ||
| 1670 | const import_lookup_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{ | ||
| 1671 | .size = addr_size * 2, | ||
| 1672 | .alignment = addr_align, | ||
| 1673 | .moved = true, | ||
| 1674 | }); | ||
| 1675 | const import_address_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{ | ||
| 1676 | .size = addr_size * 2, | ||
| 1677 | .alignment = addr_align, | ||
| 1678 | .moved = true, | ||
| 1679 | }); | ||
| 1680 | const import_address_table_si = coff.addSymbolAssumeCapacity(); | ||
| 1681 | { | ||
| 1682 | const import_address_table_sym = import_address_table_si.get(coff); | ||
| 1683 | import_address_table_sym.ni = import_address_table_ni; | ||
| 1684 | assert(import_address_table_sym.loc_relocs == .none); | ||
| 1685 | import_address_table_sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | ||
| 1686 | import_address_table_sym.section_number = Symbol.Index.idata.get(coff).section_number; | ||
| 1687 | } | ||
| 1688 | const import_hint_name_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{ | ||
| 1689 | .size = import_hint_name_table_len, | ||
| 1690 | .alignment = import_hint_name_align, | ||
| 1691 | .moved = true, | ||
| 1692 | }); | ||
| 1693 | gop.value_ptr.* = .{ | ||
| 1694 | .import_lookup_table_ni = import_lookup_table_ni, | ||
| 1695 | .import_address_table_si = import_address_table_si, | ||
| 1696 | .import_hint_name_table_ni = import_hint_name_table_ni, | ||
| 1697 | .len = 0, | ||
| 1698 | .hint_name_len = @intCast(import_hint_name_table_len), | ||
| 1699 | }; | ||
| 1700 | const import_hint_name_slice = import_hint_name_table_ni.slice(&coff.mf); | ||
| 1701 | @memcpy(import_hint_name_slice[0..lib_name.len], lib_name); | ||
| 1702 | @memcpy(import_hint_name_slice[lib_name.len..][0..".dll".len], ".dll"); | ||
| 1703 | @memset(import_hint_name_slice[lib_name.len + ".dll".len ..], 0); | ||
| 1704 | coff.nodes.appendAssumeCapacity(.{ .import_lookup_table = @intCast(gop.index) }); | ||
| 1705 | coff.nodes.appendAssumeCapacity(.{ .import_address_table = @intCast(gop.index) }); | ||
| 1706 | coff.nodes.appendAssumeCapacity(.{ .import_hint_name_table = @intCast(gop.index) }); | ||
| 1707 | |||
| 1708 | const import_directory_table: []std.coff.ImportDirectoryEntry = | ||
| 1709 | @ptrCast(@alignCast(coff.import_table.directory_table_ni.slice(&coff.mf))); | ||
| 1710 | import_directory_table[gop.index..][0..2].* = .{ .{ | ||
| 1711 | .import_lookup_table_rva = coff.computeNodeRva(import_lookup_table_ni), | ||
| 1712 | .time_date_stamp = 0, | ||
| 1713 | .forwarder_chain = 0, | ||
| 1714 | .name_rva = coff.computeNodeRva(import_hint_name_table_ni), | ||
| 1715 | .import_address_table_rva = coff.computeNodeRva(import_address_table_ni), | ||
| 1716 | }, .{ | ||
| 1717 | .import_lookup_table_rva = 0, | ||
| 1718 | .time_date_stamp = 0, | ||
| 1719 | .forwarder_chain = 0, | ||
| 1720 | .name_rva = 0, | ||
| 1721 | .import_address_table_rva = 0, | ||
| 1722 | } }; | ||
| 1723 | } | ||
| 1724 | const import_symbol_index = gop.value_ptr.len; | ||
| 1725 | gop.value_ptr.len = import_symbol_index + 1; | ||
| 1726 | const new_symbol_table_size = addr_size * (import_symbol_index + 2); | ||
| 1727 | const import_hint_name_index = gop.value_ptr.hint_name_len; | ||
| 1728 | gop.value_ptr.hint_name_len = @intCast( | ||
| 1729 | import_hint_name_align.forward(import_hint_name_index + 2 + name.len + 1), | ||
| 1730 | ); | ||
| 1731 | try gop.value_ptr.import_lookup_table_ni.resize(&coff.mf, gpa, new_symbol_table_size); | ||
| 1732 | const import_address_table_ni = gop.value_ptr.import_address_table_si.node(coff); | ||
| 1733 | try import_address_table_ni.resize(&coff.mf, gpa, new_symbol_table_size); | ||
| 1734 | try gop.value_ptr.import_hint_name_table_ni.resize(&coff.mf, gpa, gop.value_ptr.hint_name_len); | ||
| 1735 | const import_lookup_slice = gop.value_ptr.import_lookup_table_ni.slice(&coff.mf); | ||
| 1736 | const import_address_slice = import_address_table_ni.slice(&coff.mf); | ||
| 1737 | const import_hint_name_slice = gop.value_ptr.import_hint_name_table_ni.slice(&coff.mf); | ||
| 1738 | @memset(import_hint_name_slice[import_hint_name_index..][0..2], 0); | ||
| 1739 | @memcpy(import_hint_name_slice[import_hint_name_index + 2 ..][0..name.len], name); | ||
| 1740 | @memset(import_hint_name_slice[import_hint_name_index + 2 + name.len ..], 0); | ||
| 1741 | const import_hint_name_rva = | ||
| 1742 | coff.computeNodeRva(gop.value_ptr.import_hint_name_table_ni) + import_hint_name_index; | ||
| 1743 | switch (magic) { | ||
| 1744 | _ => unreachable, | ||
| 1745 | inline .PE32, .@"PE32+" => |ct_magic| { | ||
| 1746 | const Addr = switch (ct_magic) { | ||
| 1747 | _ => comptime unreachable, | ||
| 1748 | .PE32 => u32, | ||
| 1749 | .@"PE32+" => u64, | ||
| 1750 | }; | ||
| 1751 | const import_lookup_table: []Addr = @ptrCast(@alignCast(import_lookup_slice)); | ||
| 1752 | const import_address_table: []Addr = @ptrCast(@alignCast(import_address_slice)); | ||
| 1753 | const import_hint_name_rvas: [2]Addr = .{ | ||
| 1754 | std.mem.nativeTo(Addr, @intCast(import_hint_name_rva), target_endian), | ||
| 1755 | std.mem.nativeTo(Addr, 0, target_endian), | ||
| 1756 | }; | ||
| 1757 | import_lookup_table[import_symbol_index..][0..2].* = import_hint_name_rvas; | ||
| 1758 | import_address_table[import_symbol_index..][0..2].* = import_hint_name_rvas; | ||
| 1759 | }, | ||
| 1760 | } | ||
| 1761 | const si = gmi.symbol(coff); | ||
| 1762 | const sym = si.get(coff); | ||
| 1763 | sym.section_number = Symbol.Index.text.get(coff).section_number; | ||
| 1764 | assert(sym.loc_relocs == .none); | ||
| 1765 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | ||
| 1766 | switch (coff.targetLoad(&coff.headerPtr().machine)) { | ||
| 1767 | else => |tag| @panic(@tagName(tag)), | ||
| 1768 | .AMD64 => { | ||
| 1769 | const init = [_]u8{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }; | ||
| 1770 | const target = &comp.root_mod.resolved_target.result; | ||
| 1771 | const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.text.node(coff), .{ | ||
| 1772 | .alignment = switch (comp.root_mod.optimize_mode) { | ||
| 1773 | .Debug, | ||
| 1774 | .ReleaseSafe, | ||
| 1775 | .ReleaseFast, | ||
| 1776 | => target_util.defaultFunctionAlignment(target), | ||
| 1777 | .ReleaseSmall => target_util.minFunctionAlignment(target), | ||
| 1778 | }.toStdMem(), | ||
| 1779 | .size = init.len, | ||
| 1780 | }); | ||
| 1781 | @memcpy(ni.slice(&coff.mf)[0..init.len], &init); | ||
| 1782 | sym.ni = ni; | ||
| 1783 | sym.size = init.len; | ||
| 1784 | try coff.addReloc( | ||
| 1785 | si, | ||
| 1786 | init.len - 4, | ||
| 1787 | gop.value_ptr.import_address_table_si, | ||
| 1788 | @intCast(addr_size * import_symbol_index), | ||
| 1789 | .{ .AMD64 = .REL32 }, | ||
| 1790 | ); | ||
| 1791 | }, | ||
| 1792 | } | ||
| 1793 | coff.nodes.appendAssumeCapacity(.{ .global = gmi }); | ||
| 1794 | sym.rva = coff.computeNodeRva(sym.ni); | ||
| 1795 | si.applyLocationRelocs(coff); | ||
| 1796 | } | ||
| 1797 | } | ||
| 1798 | |||
| 1799 | fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { | ||
| 1800 | const zcu = pt.zcu; | ||
| 1801 | const gpa = zcu.gpa; | ||
| 1802 | |||
| 1803 | const lazy = lmr.lazySymbol(coff); | ||
| 1804 | const si = lmr.symbol(coff); | ||
| 1805 | const ni = ni: { | ||
| 1806 | const sym = si.get(coff); | ||
| 1807 | switch (sym.ni) { | ||
| 1808 | .none => { | ||
| 1809 | try coff.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 1810 | const sec_si: Symbol.Index = switch (lazy.kind) { | ||
| 1811 | .code => .text, | ||
| 1812 | .const_data => .rdata, | ||
| 1813 | }; | ||
| 1814 | const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{ .moved = true }); | ||
| 1815 | coff.nodes.appendAssumeCapacity(switch (lazy.kind) { | ||
| 1816 | .code => .{ .lazy_code = @enumFromInt(lmr.index) }, | ||
| 1817 | .const_data => .{ .lazy_const_data = @enumFromInt(lmr.index) }, | ||
| 1818 | }); | ||
| 1819 | sym.ni = ni; | ||
| 1820 | sym.section_number = sec_si.get(coff).section_number; | ||
| 1821 | }, | ||
| 1822 | else => si.deleteLocationRelocs(coff), | ||
| 1823 | } | ||
| 1824 | assert(sym.loc_relocs == .none); | ||
| 1825 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | ||
| 1826 | break :ni sym.ni; | ||
| 1827 | }; | ||
| 1828 | |||
| 1829 | var required_alignment: InternPool.Alignment = .none; | ||
| 1830 | var nw: MappedFile.Node.Writer = undefined; | ||
| 1831 | ni.writer(&coff.mf, gpa, &nw); | ||
| 1832 | defer nw.deinit(); | ||
| 1833 | try codegen.generateLazySymbol( | ||
| 1834 | &coff.base, | ||
| 1835 | pt, | ||
| 1836 | Type.fromInterned(lazy.ty).srcLocOrNull(pt.zcu) orelse .unneeded, | ||
| 1837 | lazy, | ||
| 1838 | &required_alignment, | ||
| 1839 | &nw.interface, | ||
| 1840 | .none, | ||
| 1841 | .{ .atom_index = @intFromEnum(si) }, | ||
| 1842 | ); | ||
| 1843 | si.get(coff).size = @intCast(nw.interface.end); | ||
| 1844 | si.applyLocationRelocs(coff); | ||
| 1845 | } | ||
| 1846 | |||
| 1847 | fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { | ||
| 1848 | const node = coff.getNode(ni); | ||
| 1849 | switch (node) { | ||
| 1850 | else => |tag| @panic(@tagName(tag)), | ||
| 1851 | .section => |si| return coff.targetStore( | ||
| 1852 | &si.get(coff).section_number.header(coff).pointer_to_raw_data, | ||
| 1853 | @intCast(ni.fileLocation(&coff.mf, false).offset), | ||
| 1854 | ), | ||
| 1855 | .import_directory_table => {}, | ||
| 1856 | .import_lookup_table => |import_directory_table_index| { | ||
| 1857 | const import_directory_table: []std.coff.ImportDirectoryEntry = | ||
| 1858 | @ptrCast(@alignCast(coff.import_table.directory_table_ni.slice(&coff.mf))); | ||
| 1859 | const import_directory_entry = &import_directory_table[import_directory_table_index]; | ||
| 1860 | coff.targetStore(&import_directory_entry.import_lookup_table_rva, coff.computeNodeRva(ni)); | ||
| 1861 | }, | ||
| 1862 | .import_address_table => |import_directory_table_index| { | ||
| 1863 | const import_directory_table: []std.coff.ImportDirectoryEntry = | ||
| 1864 | @ptrCast(@alignCast(coff.import_table.directory_table_ni.slice(&coff.mf))); | ||
| 1865 | const import_directory_entry = &import_directory_table[import_directory_table_index]; | ||
| 1866 | coff.targetStore(&import_directory_entry.import_lookup_table_rva, coff.computeNodeRva(ni)); | ||
| 1867 | const import_address_table_si = | ||
| 1868 | coff.import_table.dlls.values()[import_directory_table_index].import_address_table_si; | ||
| 1869 | import_address_table_si.flushMoved(coff); | ||
| 1870 | coff.targetStore( | ||
| 1871 | &import_directory_entry.import_address_table_rva, | ||
| 1872 | import_address_table_si.get(coff).rva, | ||
| 1873 | ); | ||
| 1874 | }, | ||
| 1875 | .import_hint_name_table => |import_directory_table_index| { | ||
| 1876 | const target_endian = coff.targetEndian(); | ||
| 1877 | const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic); | ||
| 1878 | const import_directory_table: []std.coff.ImportDirectoryEntry = | ||
| 1879 | @ptrCast(@alignCast(coff.import_table.directory_table_ni.slice(&coff.mf))); | ||
| 1880 | const import_directory_entry = &import_directory_table[import_directory_table_index]; | ||
| 1881 | const import_hint_name_rva = coff.computeNodeRva(ni); | ||
| 1882 | coff.targetStore(&import_directory_entry.name_rva, import_hint_name_rva); | ||
| 1883 | const import_entry = &coff.import_table.dlls.values()[import_directory_table_index]; | ||
| 1884 | const import_lookup_slice = import_entry.import_lookup_table_ni.slice(&coff.mf); | ||
| 1885 | const import_address_slice = | ||
| 1886 | import_entry.import_address_table_si.node(coff).slice(&coff.mf); | ||
| 1887 | const import_hint_name_slice = ni.slice(&coff.mf); | ||
| 1888 | const import_hint_name_align = ni.alignment(&coff.mf); | ||
| 1889 | var import_hint_name_index: u32 = 0; | ||
| 1890 | for (0..import_entry.len) |import_symbol_index| { | ||
| 1891 | import_hint_name_index = @intCast(import_hint_name_align.forward( | ||
| 1892 | std.mem.indexOfScalarPos( | ||
| 1893 | u8, | ||
| 1894 | import_hint_name_slice, | ||
| 1895 | import_hint_name_index, | ||
| 1896 | 0, | ||
| 1897 | ).? + 1, | ||
| 1898 | )); | ||
| 1899 | switch (magic) { | ||
| 1900 | _ => unreachable, | ||
| 1901 | inline .PE32, .@"PE32+" => |ct_magic| { | ||
| 1902 | const Addr = switch (ct_magic) { | ||
| 1903 | _ => comptime unreachable, | ||
| 1904 | .PE32 => u32, | ||
| 1905 | .@"PE32+" => u64, | ||
| 1906 | }; | ||
| 1907 | const import_lookup_table: []Addr = @ptrCast(@alignCast(import_lookup_slice)); | ||
| 1908 | const import_address_table: []Addr = @ptrCast(@alignCast(import_address_slice)); | ||
| 1909 | const rva = std.mem.nativeTo( | ||
| 1910 | Addr, | ||
| 1911 | import_hint_name_rva + import_hint_name_index, | ||
| 1912 | target_endian, | ||
| 1913 | ); | ||
| 1914 | import_lookup_table[import_symbol_index] = rva; | ||
| 1915 | import_address_table[import_symbol_index] = rva; | ||
| 1916 | }, | ||
| 1917 | } | ||
| 1918 | import_hint_name_index += 2; | ||
| 1919 | } | ||
| 1920 | }, | ||
| 1921 | inline .global, | ||
| 1922 | .nav, | ||
| 1923 | .uav, | ||
| 1924 | .lazy_code, | ||
| 1925 | .lazy_const_data, | ||
| 1926 | => |mi| mi.symbol(coff).flushMoved(coff), | ||
| 1927 | } | ||
| 1928 | try ni.childrenMoved(coff.base.comp.gpa, &coff.mf); | ||
| 1929 | } | ||
| 1930 | |||
| 1931 | fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { | ||
| 1932 | _, const size = ni.location(&coff.mf).resolve(&coff.mf); | ||
| 1933 | const node = coff.getNode(ni); | ||
| 1934 | switch (node) { | ||
| 1935 | else => |tag| @panic(@tagName(tag)), | ||
| 1936 | .file => {}, | ||
| 1937 | .header => { | ||
| 1938 | switch (coff.optionalHeaderPtr()) { | ||
| 1939 | inline else => |optional_header| coff.targetStore( | ||
| 1940 | &optional_header.size_of_headers, | ||
| 1941 | @intCast(size), | ||
| 1942 | ), | ||
| 1943 | } | ||
| 1944 | if (size > coff.section_table.items[0].get(coff).rva) try coff.virtualSlide( | ||
| 1945 | 0, | ||
| 1946 | std.mem.alignForward( | ||
| 1947 | u32, | ||
| 1948 | @intCast(size * 4), | ||
| 1949 | coff.optionalHeaderField(.section_alignment), | ||
| 1950 | ), | ||
| 1951 | ); | ||
| 1952 | }, | ||
| 1953 | .section_table => {}, | ||
| 1954 | .section => |si| { | ||
| 1955 | const sym = si.get(coff); | ||
| 1956 | const section_table = coff.sectionTableSlice(); | ||
| 1957 | const section_index = sym.section_number.toIndex(); | ||
| 1958 | const section = &section_table[section_index]; | ||
| 1959 | coff.targetStore(&section.size_of_raw_data, @intCast(size)); | ||
| 1960 | if (size > coff.targetLoad(&section.virtual_size)) { | ||
| 1961 | const virtual_size = std.mem.alignForward( | ||
| 1962 | u32, | ||
| 1963 | @intCast(size * 4), | ||
| 1964 | coff.optionalHeaderField(.section_alignment), | ||
| 1965 | ); | ||
| 1966 | coff.targetStore(&section.virtual_size, virtual_size); | ||
| 1967 | if (sym.data_directory) |data_directory| | ||
| 1968 | coff.dataDirectoriesSlice()[@intFromEnum(data_directory)].size = | ||
| 1969 | section.virtual_size; | ||
| 1970 | try coff.virtualSlide(section_index + 1, sym.rva + virtual_size); | ||
| 1971 | } | ||
| 1972 | }, | ||
| 1973 | .import_directory_table, | ||
| 1974 | .import_lookup_table, | ||
| 1975 | .import_address_table, | ||
| 1976 | .import_hint_name_table, | ||
| 1977 | .global, | ||
| 1978 | .nav, | ||
| 1979 | .uav, | ||
| 1980 | .lazy_code, | ||
| 1981 | .lazy_const_data, | ||
| 1982 | => {}, | ||
| 1983 | } | ||
| 1984 | } | ||
| 1985 | |||
| 1986 | fn virtualSlide(coff: *Coff, start_section_index: usize, start_rva: u32) !void { | ||
| 1987 | const section_table = coff.sectionTableSlice(); | ||
| 1988 | var rva = start_rva; | ||
| 1989 | for ( | ||
| 1990 | coff.section_table.items[start_section_index..], | ||
| 1991 | section_table[start_section_index..], | ||
| 1992 | ) |section_si, *section| { | ||
| 1993 | const section_sym = section_si.get(coff); | ||
| 1994 | section_sym.rva = rva; | ||
| 1995 | coff.targetStore(&section.virtual_address, rva); | ||
| 1996 | if (section_sym.data_directory) |data_directory| | ||
| 1997 | coff.dataDirectoriesSlice()[@intFromEnum(data_directory)].virtual_address = | ||
| 1998 | section.virtual_address; | ||
| 1999 | try section_sym.ni.childrenMoved(coff.base.comp.gpa, &coff.mf); | ||
| 2000 | rva += coff.targetLoad(&section.virtual_size); | ||
| 2001 | } | ||
| 2002 | switch (coff.optionalHeaderPtr()) { | ||
| 2003 | inline else => |optional_header| coff.targetStore( | ||
| 2004 | &optional_header.size_of_image, | ||
| 2005 | @intCast(rva), | ||
| 2006 | ), | ||
| 2007 | } | ||
| 2008 | } | ||
| 2009 | |||
| 2010 | pub fn updateExports( | ||
| 2011 | coff: *Coff, | ||
| 2012 | pt: Zcu.PerThread, | ||
| 2013 | exported: Zcu.Exported, | ||
| 2014 | export_indices: []const Zcu.Export.Index, | ||
| 2015 | ) !void { | ||
| 2016 | return coff.updateExportsInner(pt, exported, export_indices) catch |err| switch (err) { | ||
| 2017 | error.OutOfMemory => error.OutOfMemory, | ||
| 2018 | error.LinkFailure => error.AnalysisFail, | ||
| 2019 | }; | ||
| 2020 | } | ||
| 2021 | fn updateExportsInner( | ||
| 2022 | coff: *Coff, | ||
| 2023 | pt: Zcu.PerThread, | ||
| 2024 | exported: Zcu.Exported, | ||
| 2025 | export_indices: []const Zcu.Export.Index, | ||
| 2026 | ) !void { | ||
| 2027 | const zcu = pt.zcu; | ||
| 2028 | const gpa = zcu.gpa; | ||
| 2029 | const ip = &zcu.intern_pool; | ||
| 2030 | |||
| 2031 | switch (exported) { | ||
| 2032 | .nav => |nav| log.debug("updateExports({f})", .{ip.getNav(nav).fqn.fmt(ip)}), | ||
| 2033 | .uav => |uav| log.debug("updateExports(@as({f}, {f}))", .{ | ||
| 2034 | Type.fromInterned(ip.typeOf(uav)).fmt(pt), | ||
| 2035 | Value.fromInterned(uav).fmtValue(pt), | ||
| 2036 | }), | ||
| 2037 | } | ||
| 2038 | try coff.symbol_table.ensureUnusedCapacity(gpa, export_indices.len); | ||
| 2039 | const exported_si: Symbol.Index = switch (exported) { | ||
| 2040 | .nav => |nav| try coff.navSymbol(zcu, nav), | ||
| 2041 | .uav => |uav| @enumFromInt(switch (try coff.lowerUav( | ||
| 2042 | pt, | ||
| 2043 | uav, | ||
| 2044 | Type.fromInterned(ip.typeOf(uav)).abiAlignment(zcu), | ||
| 2045 | export_indices[0].ptr(zcu).src, | ||
| 2046 | )) { | ||
| 2047 | .sym_index => |si| si, | ||
| 2048 | .fail => |em| { | ||
| 2049 | defer em.destroy(gpa); | ||
| 2050 | return coff.base.comp.link_diags.fail("{s}", .{em.msg}); | ||
| 2051 | }, | ||
| 2052 | }), | ||
| 2053 | }; | ||
| 2054 | while (try coff.idle(pt.tid)) {} | ||
| 2055 | const exported_ni = exported_si.node(coff); | ||
| 2056 | const exported_sym = exported_si.get(coff); | ||
| 2057 | for (export_indices) |export_index| { | ||
| 2058 | const @"export" = export_index.ptr(zcu); | ||
| 2059 | const export_si = try coff.globalSymbol(@"export".opts.name.toSlice(ip), null); | ||
| 2060 | const export_sym = export_si.get(coff); | ||
| 2061 | export_sym.ni = exported_ni; | ||
| 2062 | export_sym.rva = exported_sym.rva; | ||
| 2063 | export_sym.size = exported_sym.size; | ||
| 2064 | export_sym.section_number = exported_sym.section_number; | ||
| 2065 | export_si.applyTargetRelocs(coff); | ||
| 2066 | if (@"export".opts.name.eqlSlice("wWinMainCRTStartup", ip)) { | ||
| 2067 | coff.entry_hack = exported_si; | ||
| 2068 | coff.optionalHeaderStandardPtr().address_of_entry_point = exported_sym.rva; | ||
| 2069 | } | ||
| 2070 | } | ||
| 2071 | } | ||
| 2072 | |||
| 2073 | pub fn deleteExport(coff: *Coff, exported: Zcu.Exported, name: InternPool.NullTerminatedString) void { | ||
| 2074 | _ = coff; | ||
| 2075 | _ = exported; | ||
| 2076 | _ = name; | ||
| 2077 | } | ||
| 2078 | |||
| 2079 | pub fn dump(coff: *Coff, tid: Zcu.PerThread.Id) void { | ||
| 2080 | const w = std.debug.lockStderrWriter(&.{}); | ||
| 2081 | defer std.debug.unlockStderrWriter(); | ||
| 2082 | coff.printNode(tid, w, .root, 0) catch {}; | ||
| 2083 | } | ||
| 2084 | |||
| 2085 | pub fn printNode( | ||
| 2086 | coff: *Coff, | ||
| 2087 | tid: Zcu.PerThread.Id, | ||
| 2088 | w: *std.Io.Writer, | ||
| 2089 | ni: MappedFile.Node.Index, | ||
| 2090 | indent: usize, | ||
| 2091 | ) !void { | ||
| 2092 | const node = coff.getNode(ni); | ||
| 2093 | try w.splatByteAll(' ', indent); | ||
| 2094 | try w.writeAll(@tagName(node)); | ||
| 2095 | switch (node) { | ||
| 2096 | else => {}, | ||
| 2097 | .section => |si| try w.print("({s})", .{ | ||
| 2098 | std.mem.sliceTo(&si.get(coff).section_number.header(coff).name, 0), | ||
| 2099 | }), | ||
| 2100 | .import_lookup_table, | ||
| 2101 | .import_address_table, | ||
| 2102 | .import_hint_name_table, | ||
| 2103 | => |import_directory_table_index| try w.print("({s})", .{ | ||
| 2104 | std.mem.sliceTo(coff.import_table.dlls.values()[import_directory_table_index] | ||
| 2105 | .import_hint_name_table_ni.sliceConst(&coff.mf), 0), | ||
| 2106 | }), | ||
| 2107 | .global => |gmi| { | ||
| 2108 | const gn = gmi.globalName(coff); | ||
| 2109 | try w.writeByte('('); | ||
| 2110 | if (gn.lib_name.toSlice(coff)) |lib_name| try w.print("{s}.dll, ", .{lib_name}); | ||
| 2111 | try w.print("{s})", .{gn.name.toSlice(coff)}); | ||
| 2112 | }, | ||
| 2113 | .nav => |nmi| { | ||
| 2114 | const zcu = coff.base.comp.zcu.?; | ||
| 2115 | const ip = &zcu.intern_pool; | ||
| 2116 | const nav = ip.getNav(nmi.navIndex(coff)); | ||
| 2117 | try w.print("({f}, {f})", .{ | ||
| 2118 | Type.fromInterned(nav.typeOf(ip)).fmt(.{ .zcu = zcu, .tid = tid }), | ||
| 2119 | nav.fqn.fmt(ip), | ||
| 2120 | }); | ||
| 2121 | }, | ||
| 2122 | .uav => |umi| { | ||
| 2123 | const zcu = coff.base.comp.zcu.?; | ||
| 2124 | const val: Value = .fromInterned(umi.uavValue(coff)); | ||
| 2125 | try w.print("({f}, {f})", .{ | ||
| 2126 | val.typeOf(zcu).fmt(.{ .zcu = zcu, .tid = tid }), | ||
| 2127 | val.fmtValue(.{ .zcu = zcu, .tid = tid }), | ||
| 2128 | }); | ||
| 2129 | }, | ||
| 2130 | inline .lazy_code, .lazy_const_data => |lmi| try w.print("({f})", .{ | ||
| 2131 | Type.fromInterned(lmi.lazySymbol(coff).ty).fmt(.{ | ||
| 2132 | .zcu = coff.base.comp.zcu.?, | ||
| 2133 | .tid = tid, | ||
| 2134 | }), | ||
| 2135 | }), | ||
| 2136 | } | ||
| 2137 | { | ||
| 2138 | const mf_node = &coff.mf.nodes.items[@intFromEnum(ni)]; | ||
| 2139 | const off, const size = mf_node.location().resolve(&coff.mf); | ||
| 2140 | try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x}{s}{s}{s}{s}\n", .{ | ||
| 2141 | @intFromEnum(ni), | ||
| 2142 | off, | ||
| 2143 | size, | ||
| 2144 | mf_node.flags.alignment.toByteUnits(), | ||
| 2145 | if (mf_node.flags.fixed) " fixed" else "", | ||
| 2146 | if (mf_node.flags.moved) " moved" else "", | ||
| 2147 | if (mf_node.flags.resized) " resized" else "", | ||
| 2148 | if (mf_node.flags.has_content) " has_content" else "", | ||
| 2149 | }); | ||
| 2150 | } | ||
| 2151 | var leaf = true; | ||
| 2152 | var child_it = ni.children(&coff.mf); | ||
| 2153 | while (child_it.next()) |child_ni| { | ||
| 2154 | leaf = false; | ||
| 2155 | try coff.printNode(tid, w, child_ni, indent + 1); | ||
| 2156 | } | ||
| 2157 | if (leaf) { | ||
| 2158 | const file_loc = ni.fileLocation(&coff.mf, false); | ||
| 2159 | if (file_loc.size == 0) return; | ||
| 2160 | var address = file_loc.offset; | ||
| 2161 | const line_len = 0x10; | ||
| 2162 | var line_it = std.mem.window( | ||
| 2163 | u8, | ||
| 2164 | coff.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)], | ||
| 2165 | line_len, | ||
| 2166 | line_len, | ||
| 2167 | ); | ||
| 2168 | while (line_it.next()) |line_bytes| : (address += line_len) { | ||
| 2169 | try w.splatByteAll(' ', indent + 1); | ||
| 2170 | try w.print("{x:0>8} ", .{address}); | ||
| 2171 | for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte}); | ||
| 2172 | try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1); | ||
| 2173 | for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.'); | ||
| 2174 | try w.writeByte('\n'); | ||
| 2175 | } | ||
| 2176 | } | ||
| 2177 | } | ||
| 2178 | |||
| 2179 | const assert = std.debug.assert; | ||
| 2180 | const builtin = @import("builtin"); | ||
| 2181 | const codegen = @import("../codegen.zig"); | ||
| 2182 | const Compilation = @import("../Compilation.zig"); | ||
| 2183 | const Coff = @This(); | ||
| 2184 | const InternPool = @import("../InternPool.zig"); | ||
| 2185 | const link = @import("../link.zig"); | ||
| 2186 | const log = std.log.scoped(.link); | ||
| 2187 | const MappedFile = @import("MappedFile.zig"); | ||
| 2188 | const native_endian = builtin.cpu.arch.endian(); | ||
| 2189 | const std = @import("std"); | ||
| 2190 | const target_util = @import("../target.zig"); | ||
| 2191 | const Type = @import("../Type.zig"); | ||
| 2192 | const Value = @import("../Value.zig"); | ||
| 2193 | const Zcu = @import("../Zcu.zig"); | ||
src/link/Elf2.zig+440-456| ... | @@ -1,6 +1,8 @@ | ... | @@ -1,6 +1,8 @@ |
| 1 | base: link.File, | 1 | base: link.File, |
| 2 | mf: MappedFile, | 2 | mf: MappedFile, |
| 3 | known: Node.Known, | ||
| 3 | nodes: std.MultiArrayList(Node), | 4 | nodes: std.MultiArrayList(Node), |
| 5 | phdrs: std.ArrayList(MappedFile.Node.Index), | ||
| 4 | symtab: std.ArrayList(Symbol), | 6 | symtab: std.ArrayList(Symbol), |
| 5 | shstrtab: StringTable, | 7 | shstrtab: StringTable, |
| 6 | strtab: StringTable, | 8 | strtab: StringTable, |
| ... | @@ -85,23 +87,15 @@ pub const Node = union(enum) { | ... | @@ -85,23 +87,15 @@ pub const Node = union(enum) { |
| 85 | } | 87 | } |
| 86 | }; | 88 | }; |
| 87 | 89 | ||
| 88 | pub const Tag = @typeInfo(Node).@"union".tag_type.?; | 90 | pub const Known = struct { |
| 89 | 91 | pub const rodata: MappedFile.Node.Index = @enumFromInt(1); | |
| 90 | const known_count = @typeInfo(@TypeOf(known)).@"struct".fields.len; | 92 | pub const ehdr: MappedFile.Node.Index = @enumFromInt(2); |
| 91 | const known = known: { | 93 | pub const phdr: MappedFile.Node.Index = @enumFromInt(3); |
| 92 | const Known = enum { | 94 | pub const shdr: MappedFile.Node.Index = @enumFromInt(4); |
| 93 | file, | 95 | pub const text: MappedFile.Node.Index = @enumFromInt(5); |
| 94 | seg_rodata, | 96 | pub const data: MappedFile.Node.Index = @enumFromInt(6); |
| 95 | ehdr, | 97 | |
| 96 | phdr, | 98 | tls: MappedFile.Node.Index, |
| 97 | shdr, | ||
| 98 | seg_text, | ||
| 99 | seg_data, | ||
| 100 | }; | ||
| 101 | var mut_known: std.enums.EnumFieldStruct(Known, MappedFile.Node.Index, null) = undefined; | ||
| 102 | for (@typeInfo(Known).@"enum".fields) |field| | ||
| 103 | @field(mut_known, field.name) = @enumFromInt(field.value); | ||
| 104 | break :known mut_known; | ||
| 105 | }; | 99 | }; |
| 106 | 100 | ||
| 107 | comptime { | 101 | comptime { |
| ... | @@ -231,6 +225,21 @@ pub const Symbol = struct { | ... | @@ -231,6 +225,21 @@ pub const Symbol = struct { |
| 231 | } | 225 | } |
| 232 | } | 226 | } |
| 233 | 227 | ||
| 228 | pub fn flushMoved(si: Symbol.Index, elf: *Elf) void { | ||
| 229 | const value = elf.computeNodeVAddr(si.node(elf)); | ||
| 230 | switch (elf.symPtr(si)) { | ||
| 231 | inline else => |sym, class| { | ||
| 232 | elf.targetStore(&sym.value, @intCast(value)); | ||
| 233 | if (si == elf.entry_hack) { | ||
| 234 | @branchHint(.unlikely); | ||
| 235 | @field(elf.ehdrPtr(), @tagName(class)).entry = sym.value; | ||
| 236 | } | ||
| 237 | }, | ||
| 238 | } | ||
| 239 | si.applyLocationRelocs(elf); | ||
| 240 | si.applyTargetRelocs(elf); | ||
| 241 | } | ||
| 242 | |||
| 234 | pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void { | 243 | pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void { |
| 235 | for (elf.relocs.items[@intFromEnum(si.get(elf).loc_relocs)..]) |*reloc| { | 244 | for (elf.relocs.items[@intFromEnum(si.get(elf).loc_relocs)..]) |*reloc| { |
| 236 | if (reloc.loc != si) break; | 245 | if (reloc.loc != si) break; |
| ... | @@ -290,8 +299,8 @@ pub const Reloc = extern struct { | ... | @@ -290,8 +299,8 @@ pub const Reloc = extern struct { |
| 290 | }; | 299 | }; |
| 291 | 300 | ||
| 292 | pub fn apply(reloc: *const Reloc, elf: *Elf) void { | 301 | pub fn apply(reloc: *const Reloc, elf: *Elf) void { |
| 293 | const target_endian = elf.targetEndian(); | 302 | const loc_ni = reloc.loc.get(elf).ni; |
| 294 | switch (reloc.loc.get(elf).ni) { | 303 | switch (loc_ni) { |
| 295 | .none => return, | 304 | .none => return, |
| 296 | else => |ni| if (ni.hasMoved(&elf.mf)) return, | 305 | else => |ni| if (ni.hasMoved(&elf.mf)) return, |
| 297 | } | 306 | } |
| ... | @@ -299,68 +308,47 @@ pub const Reloc = extern struct { | ... | @@ -299,68 +308,47 @@ pub const Reloc = extern struct { |
| 299 | .none => return, | 308 | .none => return, |
| 300 | else => |ni| if (ni.hasMoved(&elf.mf)) return, | 309 | else => |ni| if (ni.hasMoved(&elf.mf)) return, |
| 301 | } | 310 | } |
| 302 | switch (elf.shdrSlice()) { | 311 | const loc_slice = loc_ni.slice(&elf.mf)[@intCast(reloc.offset)..]; |
| 303 | inline else => |shdr, class| { | 312 | const target_endian = elf.targetEndian(); |
| 304 | const sym = @field(elf.symSlice(), @tagName(class)); | 313 | switch (elf.symtabSlice()) { |
| 305 | const loc_sym = &sym[@intFromEnum(reloc.loc)]; | 314 | inline else => |symtab, class| { |
| 306 | const loc_shndx = | 315 | const loc_sym = &symtab[@intFromEnum(reloc.loc)]; |
| 307 | std.mem.toNative(@TypeOf(loc_sym.shndx), loc_sym.shndx, target_endian); | 316 | const loc_shndx = elf.targetLoad(&loc_sym.shndx); |
| 308 | assert(loc_shndx != std.elf.SHN_UNDEF); | 317 | assert(loc_shndx != std.elf.SHN_UNDEF); |
| 309 | const loc_sh = &shdr[loc_shndx]; | 318 | const loc_value = elf.targetLoad(&loc_sym.value) + reloc.offset; |
| 310 | const loc_value = std.mem.toNative( | 319 | const target_sym = &symtab[@intFromEnum(reloc.target)]; |
| 311 | @TypeOf(loc_sym.value), | 320 | const target_value = |
| 312 | loc_sym.value, | 321 | elf.targetLoad(&target_sym.value) +% @as(u64, @bitCast(reloc.addend)); |
| 313 | target_endian, | ||
| 314 | ) + reloc.offset; | ||
| 315 | const loc_sh_addr = | ||
| 316 | std.mem.toNative(@TypeOf(loc_sh.addr), loc_sh.addr, target_endian); | ||
| 317 | const loc_sh_offset = | ||
| 318 | std.mem.toNative(@TypeOf(loc_sh.offset), loc_sh.offset, target_endian); | ||
| 319 | const loc_file_offset: usize = @intCast(loc_value - loc_sh_addr + loc_sh_offset); | ||
| 320 | const target_sym = &sym[@intFromEnum(reloc.target)]; | ||
| 321 | const target_value = std.mem.toNative( | ||
| 322 | @TypeOf(target_sym.value), | ||
| 323 | target_sym.value, | ||
| 324 | target_endian, | ||
| 325 | ) +% @as(u64, @bitCast(reloc.addend)); | ||
| 326 | switch (elf.ehdrField(.machine)) { | 322 | switch (elf.ehdrField(.machine)) { |
| 327 | else => |machine| @panic(@tagName(machine)), | 323 | else => |machine| @panic(@tagName(machine)), |
| 328 | .X86_64 => switch (reloc.type.X86_64) { | 324 | .X86_64 => switch (reloc.type.X86_64) { |
| 329 | else => |kind| @panic(@tagName(kind)), | 325 | else => |kind| @panic(@tagName(kind)), |
| 330 | .@"64" => std.mem.writeInt( | 326 | .@"64" => std.mem.writeInt( |
| 331 | u64, | 327 | u64, |
| 332 | elf.mf.contents[loc_file_offset..][0..8], | 328 | loc_slice[0..8], |
| 333 | target_value, | 329 | target_value, |
| 334 | target_endian, | 330 | target_endian, |
| 335 | ), | 331 | ), |
| 336 | .PC32 => std.mem.writeInt( | 332 | .PC32 => std.mem.writeInt( |
| 337 | i32, | 333 | i32, |
| 338 | elf.mf.contents[loc_file_offset..][0..4], | 334 | loc_slice[0..4], |
| 339 | @intCast(@as(i64, @bitCast(target_value -% loc_value))), | 335 | @intCast(@as(i64, @bitCast(target_value -% loc_value))), |
| 340 | target_endian, | 336 | target_endian, |
| 341 | ), | 337 | ), |
| 342 | .@"32" => std.mem.writeInt( | 338 | .@"32" => std.mem.writeInt( |
| 343 | u32, | 339 | u32, |
| 344 | elf.mf.contents[loc_file_offset..][0..4], | 340 | loc_slice[0..4], |
| 345 | @intCast(target_value), | 341 | @intCast(target_value), |
| 346 | target_endian, | 342 | target_endian, |
| 347 | ), | 343 | ), |
| 348 | .TPOFF32 => { | 344 | .TPOFF32 => { |
| 349 | const phdr = @field(elf.phdrSlice(), @tagName(class)); | 345 | const phdr = @field(elf.phdrSlice(), @tagName(class)); |
| 350 | const ph = &phdr[4]; | 346 | const ph = &phdr[elf.getNode(elf.known.tls).segment]; |
| 351 | assert(std.mem.toNative( | 347 | assert(elf.targetLoad(&ph.type) == std.elf.PT_TLS); |
| 352 | @TypeOf(ph.type), | ||
| 353 | ph.type, | ||
| 354 | target_endian, | ||
| 355 | ) == std.elf.PT_TLS); | ||
| 356 | std.mem.writeInt( | 348 | std.mem.writeInt( |
| 357 | i32, | 349 | i32, |
| 358 | elf.mf.contents[loc_file_offset..][0..4], | 350 | loc_slice[0..4], |
| 359 | @intCast(@as(i64, @bitCast(target_value -% std.mem.toNative( | 351 | @intCast(@as(i64, @bitCast(target_value -% elf.targetLoad(&ph.memsz)))), |
| 360 | @TypeOf(ph.memsz), | ||
| 361 | ph.memsz, | ||
| 362 | target_endian, | ||
| 363 | )))), | ||
| 364 | target_endian, | 352 | target_endian, |
| 365 | ); | 353 | ); |
| 366 | }, | 354 | }, |
| ... | @@ -475,7 +463,11 @@ fn create( | ... | @@ -475,7 +463,11 @@ fn create( |
| 475 | .stack_size = 0, | 463 | .stack_size = 0, |
| 476 | }, | 464 | }, |
| 477 | .mf = try .init(file, comp.gpa), | 465 | .mf = try .init(file, comp.gpa), |
| 466 | .known = .{ | ||
| 467 | .tls = .none, | ||
| 468 | }, | ||
| 478 | .nodes = .empty, | 469 | .nodes = .empty, |
| 470 | .phdrs = .empty, | ||
| 479 | .symtab = .empty, | 471 | .symtab = .empty, |
| 480 | .shstrtab = .{ | 472 | .shstrtab = .{ |
| 481 | .map = .empty, | 473 | .map = .empty, |
| ... | @@ -488,7 +480,7 @@ fn create( | ... | @@ -488,7 +480,7 @@ fn create( |
| 488 | .globals = .empty, | 480 | .globals = .empty, |
| 489 | .navs = .empty, | 481 | .navs = .empty, |
| 490 | .uavs = .empty, | 482 | .uavs = .empty, |
| 491 | .lazy = .initFill(.{ | 483 | .lazy = comptime .initFill(.{ |
| 492 | .map = .empty, | 484 | .map = .empty, |
| 493 | .pending_index = 0, | 485 | .pending_index = 0, |
| 494 | }), | 486 | }), |
| ... | @@ -498,18 +490,7 @@ fn create( | ... | @@ -498,18 +490,7 @@ fn create( |
| 498 | }; | 490 | }; |
| 499 | errdefer elf.deinit(); | 491 | errdefer elf.deinit(); |
| 500 | 492 | ||
| 501 | switch (class) { | 493 | try elf.initHeaders(class, data, osabi, @"type", machine, maybe_interp); |
| 502 | .NONE, _ => unreachable, | ||
| 503 | inline else => |ct_class| try elf.initHeaders( | ||
| 504 | ct_class, | ||
| 505 | data, | ||
| 506 | osabi, | ||
| 507 | @"type", | ||
| 508 | machine, | ||
| 509 | maybe_interp, | ||
| 510 | ), | ||
| 511 | } | ||
| 512 | |||
| 513 | return elf; | 494 | return elf; |
| 514 | } | 495 | } |
| 515 | 496 | ||
| ... | @@ -517,6 +498,7 @@ pub fn deinit(elf: *Elf) void { | ... | @@ -517,6 +498,7 @@ pub fn deinit(elf: *Elf) void { |
| 517 | const gpa = elf.base.comp.gpa; | 498 | const gpa = elf.base.comp.gpa; |
| 518 | elf.mf.deinit(gpa); | 499 | elf.mf.deinit(gpa); |
| 519 | elf.nodes.deinit(gpa); | 500 | elf.nodes.deinit(gpa); |
| 501 | elf.phdrs.deinit(gpa); | ||
| 520 | elf.symtab.deinit(gpa); | 502 | elf.symtab.deinit(gpa); |
| 521 | elf.shstrtab.map.deinit(gpa); | 503 | elf.shstrtab.map.deinit(gpa); |
| 522 | elf.strtab.map.deinit(gpa); | 504 | elf.strtab.map.deinit(gpa); |
| ... | @@ -531,7 +513,7 @@ pub fn deinit(elf: *Elf) void { | ... | @@ -531,7 +513,7 @@ pub fn deinit(elf: *Elf) void { |
| 531 | 513 | ||
| 532 | fn initHeaders( | 514 | fn initHeaders( |
| 533 | elf: *Elf, | 515 | elf: *Elf, |
| 534 | comptime class: std.elf.CLASS, | 516 | class: std.elf.CLASS, |
| 535 | data: std.elf.DATA, | 517 | data: std.elf.DATA, |
| 536 | osabi: std.elf.OSABI, | 518 | osabi: std.elf.OSABI, |
| 537 | @"type": std.elf.ET, | 519 | @"type": std.elf.ET, |
| ... | @@ -540,16 +522,10 @@ fn initHeaders( | ... | @@ -540,16 +522,10 @@ fn initHeaders( |
| 540 | ) !void { | 522 | ) !void { |
| 541 | const comp = elf.base.comp; | 523 | const comp = elf.base.comp; |
| 542 | const gpa = comp.gpa; | 524 | const gpa = comp.gpa; |
| 543 | const ElfN = switch (class) { | 525 | const addr_align: std.mem.Alignment = switch (class) { |
| 544 | .NONE, _ => comptime unreachable, | ||
| 545 | .@"32" => std.elf.Elf32, | ||
| 546 | .@"64" => std.elf.Elf64, | ||
| 547 | }; | ||
| 548 | const addr_align: std.mem.Alignment = comptime .fromByteUnits(@sizeOf(ElfN.Addr)); | ||
| 549 | const target_endian: std.builtin.Endian = switch (data) { | ||
| 550 | .NONE, _ => unreachable, | 526 | .NONE, _ => unreachable, |
| 551 | .@"2LSB" => .little, | 527 | .@"32" => .@"4", |
| 552 | .@"2MSB" => .big, | 528 | .@"64" => .@"8", |
| 553 | }; | 529 | }; |
| 554 | 530 | ||
| 555 | var phnum: u32 = 0; | 531 | var phnum: u32 = 0; |
| ... | @@ -570,218 +546,257 @@ fn initHeaders( | ... | @@ -570,218 +546,257 @@ fn initHeaders( |
| 570 | break :phndx phnum; | 546 | break :phndx phnum; |
| 571 | } else undefined; | 547 | } else undefined; |
| 572 | 548 | ||
| 573 | try elf.nodes.ensureTotalCapacity(gpa, Node.known_count); | 549 | const expected_nodes_len = 15; |
| 550 | try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len); | ||
| 551 | try elf.phdrs.resize(gpa, phnum); | ||
| 574 | elf.nodes.appendAssumeCapacity(.file); | 552 | elf.nodes.appendAssumeCapacity(.file); |
| 575 | 553 | ||
| 576 | const seg_rodata_ni = Node.known.seg_rodata; | 554 | assert(Node.Known.rodata == try elf.mf.addOnlyChildNode(gpa, .root, .{ |
| 577 | assert(seg_rodata_ni == try elf.mf.addOnlyChildNode(gpa, .root, .{ | ||
| 578 | .alignment = elf.mf.flags.block_size, | 555 | .alignment = elf.mf.flags.block_size, |
| 579 | .fixed = true, | 556 | .fixed = true, |
| 580 | .moved = true, | 557 | .moved = true, |
| 558 | .bubbles_moved = false, | ||
| 581 | })); | 559 | })); |
| 582 | elf.nodes.appendAssumeCapacity(.{ .segment = rodata_phndx }); | 560 | elf.nodes.appendAssumeCapacity(.{ .segment = rodata_phndx }); |
| 561 | elf.phdrs.items[rodata_phndx] = Node.Known.rodata; | ||
| 583 | 562 | ||
| 584 | const ehdr_ni = Node.known.ehdr; | 563 | switch (class) { |
| 585 | assert(ehdr_ni == try elf.mf.addOnlyChildNode(gpa, seg_rodata_ni, .{ | 564 | .NONE, _ => unreachable, |
| 586 | .size = @sizeOf(ElfN.Ehdr), | 565 | inline else => |ct_class| { |
| 587 | .alignment = addr_align, | 566 | const ElfN = switch (ct_class) { |
| 588 | .fixed = true, | 567 | .NONE, _ => comptime unreachable, |
| 589 | })); | 568 | .@"32" => std.elf.Elf32, |
| 590 | elf.nodes.appendAssumeCapacity(.ehdr); | 569 | .@"64" => std.elf.Elf64, |
| 591 | { | 570 | }; |
| 592 | const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(ehdr_ni.slice(&elf.mf))); | 571 | |
| 593 | const EI = std.elf.EI; | 572 | assert(Node.Known.ehdr == try elf.mf.addOnlyChildNode(gpa, Node.Known.rodata, .{ |
| 594 | @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC); | 573 | .size = @sizeOf(ElfN.Ehdr), |
| 595 | ehdr.ident[EI.CLASS] = @intFromEnum(class); | 574 | .alignment = addr_align, |
| 596 | ehdr.ident[EI.DATA] = @intFromEnum(data); | 575 | .fixed = true, |
| 597 | ehdr.ident[EI.VERSION] = 1; | 576 | })); |
| 598 | ehdr.ident[EI.OSABI] = @intFromEnum(osabi); | 577 | elf.nodes.appendAssumeCapacity(.ehdr); |
| 599 | ehdr.ident[EI.ABIVERSION] = 0; | 578 | |
| 600 | @memset(ehdr.ident[EI.PAD..], 0); | 579 | const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(Node.Known.ehdr.slice(&elf.mf))); |
| 601 | ehdr.type = @"type"; | 580 | const EI = std.elf.EI; |
| 602 | ehdr.machine = machine; | 581 | @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC); |
| 603 | ehdr.version = 1; | 582 | ehdr.ident[EI.CLASS] = @intFromEnum(class); |
| 604 | ehdr.entry = 0; | 583 | ehdr.ident[EI.DATA] = @intFromEnum(data); |
| 605 | ehdr.phoff = 0; | 584 | ehdr.ident[EI.VERSION] = 1; |
| 606 | ehdr.shoff = 0; | 585 | ehdr.ident[EI.OSABI] = @intFromEnum(osabi); |
| 607 | ehdr.flags = 0; | 586 | ehdr.ident[EI.ABIVERSION] = 0; |
| 608 | ehdr.ehsize = @sizeOf(ElfN.Ehdr); | 587 | @memset(ehdr.ident[EI.PAD..], 0); |
| 609 | ehdr.phentsize = @sizeOf(ElfN.Phdr); | 588 | ehdr.type = @"type"; |
| 610 | ehdr.phnum = @min(phnum, std.elf.PN_XNUM); | 589 | ehdr.machine = machine; |
| 611 | ehdr.shentsize = @sizeOf(ElfN.Shdr); | 590 | ehdr.version = 1; |
| 612 | ehdr.shnum = 1; | 591 | ehdr.entry = 0; |
| 613 | ehdr.shstrndx = 0; | 592 | ehdr.phoff = 0; |
| 614 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr); | 593 | ehdr.shoff = 0; |
| 594 | ehdr.flags = 0; | ||
| 595 | ehdr.ehsize = @sizeOf(ElfN.Ehdr); | ||
| 596 | ehdr.phentsize = @sizeOf(ElfN.Phdr); | ||
| 597 | ehdr.phnum = @min(phnum, std.elf.PN_XNUM); | ||
| 598 | ehdr.shentsize = @sizeOf(ElfN.Shdr); | ||
| 599 | ehdr.shnum = 1; | ||
| 600 | ehdr.shstrndx = std.elf.SHN_UNDEF; | ||
| 601 | if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr); | ||
| 602 | }, | ||
| 615 | } | 603 | } |
| 616 | 604 | ||
| 617 | const phdr_ni = Node.known.phdr; | 605 | assert(Node.Known.phdr == try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{ |
| 618 | assert(phdr_ni == try elf.mf.addLastChildNode(gpa, seg_rodata_ni, .{ | 606 | .size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum), |
| 619 | .size = @sizeOf(ElfN.Phdr) * phnum, | ||
| 620 | .alignment = addr_align, | 607 | .alignment = addr_align, |
| 621 | .moved = true, | 608 | .moved = true, |
| 622 | .resized = true, | 609 | .resized = true, |
| 610 | .bubbles_moved = false, | ||
| 623 | })); | 611 | })); |
| 624 | elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx }); | 612 | elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx }); |
| 613 | elf.phdrs.items[phdr_phndx] = Node.Known.phdr; | ||
| 625 | 614 | ||
| 626 | const shdr_ni = Node.known.shdr; | 615 | assert(Node.Known.shdr == try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{ |
| 627 | assert(shdr_ni == try elf.mf.addLastChildNode(gpa, seg_rodata_ni, .{ | 616 | .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum), |
| 628 | .size = @sizeOf(ElfN.Shdr), | ||
| 629 | .alignment = addr_align, | 617 | .alignment = addr_align, |
| 630 | })); | 618 | })); |
| 631 | elf.nodes.appendAssumeCapacity(.shdr); | 619 | elf.nodes.appendAssumeCapacity(.shdr); |
| 632 | 620 | ||
| 633 | const seg_text_ni = Node.known.seg_text; | 621 | assert(Node.Known.text == try elf.mf.addLastChildNode(gpa, .root, .{ |
| 634 | assert(seg_text_ni == try elf.mf.addLastChildNode(gpa, .root, .{ | ||
| 635 | .alignment = elf.mf.flags.block_size, | 622 | .alignment = elf.mf.flags.block_size, |
| 636 | .moved = true, | 623 | .moved = true, |
| 624 | .bubbles_moved = false, | ||
| 637 | })); | 625 | })); |
| 638 | elf.nodes.appendAssumeCapacity(.{ .segment = text_phndx }); | 626 | elf.nodes.appendAssumeCapacity(.{ .segment = text_phndx }); |
| 627 | elf.phdrs.items[text_phndx] = Node.Known.text; | ||
| 639 | 628 | ||
| 640 | const seg_data_ni = Node.known.seg_data; | 629 | assert(Node.Known.data == try elf.mf.addLastChildNode(gpa, .root, .{ |
| 641 | assert(seg_data_ni == try elf.mf.addLastChildNode(gpa, .root, .{ | ||
| 642 | .alignment = elf.mf.flags.block_size, | 630 | .alignment = elf.mf.flags.block_size, |
| 643 | .moved = true, | 631 | .moved = true, |
| 632 | .bubbles_moved = false, | ||
| 644 | })); | 633 | })); |
| 645 | elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx }); | 634 | elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx }); |
| 635 | elf.phdrs.items[data_phndx] = Node.Known.data; | ||
| 646 | 636 | ||
| 647 | assert(elf.nodes.len == Node.known_count); | 637 | var ph_vaddr: u32 = switch (elf.ehdrField(.type)) { |
| 648 | 638 | else => 0, | |
| 649 | { | 639 | .EXEC => switch (elf.ehdrField(.machine)) { |
| 650 | const phdr: []ElfN.Phdr = @ptrCast(@alignCast(phdr_ni.slice(&elf.mf))); | 640 | .@"386" => 0x400000, |
| 651 | const ph_phdr = &phdr[phdr_phndx]; | 641 | .AARCH64, .X86_64 => 0x200000, |
| 652 | ph_phdr.* = .{ | 642 | .PPC, .PPC64 => 0x10000000, |
| 653 | .type = std.elf.PT_PHDR, | 643 | .S390, .S390_OLD => 0x1000000, |
| 654 | .offset = 0, | 644 | .OLD_SPARCV9, .SPARCV9 => 0x100000, |
| 655 | .vaddr = 0, | 645 | else => 0x10000, |
| 656 | .paddr = 0, | 646 | }, |
| 657 | .filesz = 0, | 647 | }; |
| 658 | .memsz = 0, | 648 | switch (class) { |
| 659 | .flags = .{ .R = true }, | 649 | .NONE, _ => unreachable, |
| 660 | .@"align" = @intCast(phdr_ni.alignment(&elf.mf).toByteUnits()), | 650 | inline else => |ct_class| { |
| 661 | }; | 651 | const ElfN = switch (ct_class) { |
| 662 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr); | 652 | .NONE, _ => comptime unreachable, |
| 653 | .@"32" => std.elf.Elf32, | ||
| 654 | .@"64" => std.elf.Elf64, | ||
| 655 | }; | ||
| 656 | const target_endian = elf.targetEndian(); | ||
| 663 | 657 | ||
| 664 | if (maybe_interp) |_| { | 658 | const phdr: []ElfN.Phdr = @ptrCast(@alignCast(Node.Known.phdr.slice(&elf.mf))); |
| 665 | const ph_interp = &phdr[interp_phndx]; | 659 | const ph_phdr = &phdr[phdr_phndx]; |
| 666 | ph_interp.* = .{ | 660 | ph_phdr.* = .{ |
| 667 | .type = std.elf.PT_INTERP, | 661 | .type = std.elf.PT_PHDR, |
| 668 | .offset = 0, | 662 | .offset = 0, |
| 669 | .vaddr = 0, | 663 | .vaddr = 0, |
| 670 | .paddr = 0, | 664 | .paddr = 0, |
| 671 | .filesz = 0, | 665 | .filesz = 0, |
| 672 | .memsz = 0, | 666 | .memsz = 0, |
| 673 | .flags = .{ .R = true }, | 667 | .flags = .{ .R = true }, |
| 674 | .@"align" = 1, | 668 | .@"align" = @intCast(Node.Known.phdr.alignment(&elf.mf).toByteUnits()), |
| 675 | }; | 669 | }; |
| 676 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp); | 670 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr); |
| 677 | } | 671 | |
| 678 | 672 | if (maybe_interp) |_| { | |
| 679 | const ph_rodata = &phdr[rodata_phndx]; | 673 | const ph_interp = &phdr[interp_phndx]; |
| 680 | ph_rodata.* = .{ | 674 | ph_interp.* = .{ |
| 681 | .type = std.elf.PT_NULL, | 675 | .type = std.elf.PT_INTERP, |
| 682 | .offset = 0, | 676 | .offset = 0, |
| 683 | .vaddr = 0, | 677 | .vaddr = 0, |
| 684 | .paddr = 0, | 678 | .paddr = 0, |
| 685 | .filesz = 0, | 679 | .filesz = 0, |
| 686 | .memsz = 0, | 680 | .memsz = 0, |
| 687 | .flags = .{ .R = true }, | 681 | .flags = .{ .R = true }, |
| 688 | .@"align" = @intCast(seg_rodata_ni.alignment(&elf.mf).toByteUnits()), | 682 | .@"align" = 1, |
| 689 | }; | 683 | }; |
| 690 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata); | 684 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp); |
| 691 | 685 | } | |
| 692 | const ph_text = &phdr[text_phndx]; | ||
| 693 | ph_text.* = .{ | ||
| 694 | .type = std.elf.PT_NULL, | ||
| 695 | .offset = 0, | ||
| 696 | .vaddr = 0, | ||
| 697 | .paddr = 0, | ||
| 698 | .filesz = 0, | ||
| 699 | .memsz = 0, | ||
| 700 | .flags = .{ .R = true, .X = true }, | ||
| 701 | .@"align" = @intCast(seg_text_ni.alignment(&elf.mf).toByteUnits()), | ||
| 702 | }; | ||
| 703 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text); | ||
| 704 | |||
| 705 | const ph_data = &phdr[data_phndx]; | ||
| 706 | ph_data.* = .{ | ||
| 707 | .type = std.elf.PT_NULL, | ||
| 708 | .offset = 0, | ||
| 709 | .vaddr = 0, | ||
| 710 | .paddr = 0, | ||
| 711 | .filesz = 0, | ||
| 712 | .memsz = 0, | ||
| 713 | .flags = .{ .R = true, .W = true }, | ||
| 714 | .@"align" = @intCast(seg_data_ni.alignment(&elf.mf).toByteUnits()), | ||
| 715 | }; | ||
| 716 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data); | ||
| 717 | 686 | ||
| 718 | if (comp.config.any_non_single_threaded) { | 687 | _, const rodata_size = Node.Known.rodata.location(&elf.mf).resolve(&elf.mf); |
| 719 | const ph_tls = &phdr[tls_phndx]; | 688 | const ph_rodata = &phdr[rodata_phndx]; |
| 720 | ph_tls.* = .{ | 689 | ph_rodata.* = .{ |
| 721 | .type = std.elf.PT_TLS, | 690 | .type = std.elf.PT_NULL, |
| 722 | .offset = 0, | 691 | .offset = 0, |
| 723 | .vaddr = 0, | 692 | .vaddr = ph_vaddr, |
| 724 | .paddr = 0, | 693 | .paddr = ph_vaddr, |
| 725 | .filesz = 0, | 694 | .filesz = @intCast(rodata_size), |
| 726 | .memsz = 0, | 695 | .memsz = @intCast(rodata_size), |
| 727 | .flags = .{ .R = true }, | 696 | .flags = .{ .R = true }, |
| 728 | .@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()), | 697 | .@"align" = @intCast(Node.Known.rodata.alignment(&elf.mf).toByteUnits()), |
| 729 | }; | 698 | }; |
| 730 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls); | 699 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata); |
| 731 | } | 700 | ph_vaddr += @intCast(rodata_size); |
| 732 | 701 | ||
| 733 | const sh_null: *ElfN.Shdr = @ptrCast(@alignCast(shdr_ni.slice(&elf.mf))); | 702 | _, const text_size = Node.Known.text.location(&elf.mf).resolve(&elf.mf); |
| 734 | sh_null.* = .{ | 703 | const ph_text = &phdr[text_phndx]; |
| 735 | .name = try elf.string(.shstrtab, ""), | 704 | ph_text.* = .{ |
| 736 | .type = std.elf.SHT_NULL, | 705 | .type = std.elf.PT_NULL, |
| 737 | .flags = .{ .shf = .{} }, | 706 | .offset = 0, |
| 738 | .addr = 0, | 707 | .vaddr = ph_vaddr, |
| 739 | .offset = 0, | 708 | .paddr = ph_vaddr, |
| 740 | .size = 0, | 709 | .filesz = @intCast(text_size), |
| 741 | .link = 0, | 710 | .memsz = @intCast(text_size), |
| 742 | .info = if (phnum >= std.elf.PN_XNUM) phnum else 0, | 711 | .flags = .{ .R = true, .X = true }, |
| 743 | .addralign = 0, | 712 | .@"align" = @intCast(Node.Known.text.alignment(&elf.mf).toByteUnits()), |
| 744 | .entsize = 0, | 713 | }; |
| 745 | }; | 714 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text); |
| 746 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_null); | 715 | ph_vaddr += @intCast(text_size); |
| 747 | } | ||
| 748 | 716 | ||
| 749 | try elf.symtab.ensureTotalCapacity(gpa, 1); | 717 | _, const data_size = Node.Known.data.location(&elf.mf).resolve(&elf.mf); |
| 750 | elf.symtab.addOneAssumeCapacity().* = .{ | 718 | const ph_data = &phdr[data_phndx]; |
| 751 | .ni = .none, | 719 | ph_data.* = .{ |
| 752 | .loc_relocs = .none, | 720 | .type = std.elf.PT_NULL, |
| 753 | .target_relocs = .none, | 721 | .offset = 0, |
| 754 | .unused = 0, | 722 | .vaddr = ph_vaddr, |
| 755 | }; | 723 | .paddr = ph_vaddr, |
| 756 | assert(try elf.addSection(seg_rodata_ni, .{ | 724 | .filesz = @intCast(data_size), |
| 757 | .type = std.elf.SHT_SYMTAB, | 725 | .memsz = @intCast(data_size), |
| 758 | .addralign = addr_align, | 726 | .flags = .{ .R = true, .W = true }, |
| 759 | .entsize = @sizeOf(ElfN.Sym), | 727 | .@"align" = @intCast(Node.Known.data.alignment(&elf.mf).toByteUnits()), |
| 760 | }) == .symtab); | 728 | }; |
| 761 | const symtab: *ElfN.Sym = @ptrCast(@alignCast(Symbol.Index.symtab.node(elf).slice(&elf.mf))); | 729 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data); |
| 762 | symtab.* = .{ | 730 | ph_vaddr += @intCast(data_size); |
| 763 | .name = try elf.string(.strtab, ""), | 731 | |
| 764 | .value = 0, | 732 | if (comp.config.any_non_single_threaded) { |
| 765 | .size = 0, | 733 | const ph_tls = &phdr[tls_phndx]; |
| 766 | .info = .{ | 734 | ph_tls.* = .{ |
| 767 | .type = .NOTYPE, | 735 | .type = std.elf.PT_TLS, |
| 768 | .bind = .LOCAL, | 736 | .offset = 0, |
| 769 | }, | 737 | .vaddr = 0, |
| 770 | .other = .{ | 738 | .paddr = 0, |
| 771 | .visibility = .DEFAULT, | 739 | .filesz = 0, |
| 740 | .memsz = 0, | ||
| 741 | .flags = .{ .R = true }, | ||
| 742 | .@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()), | ||
| 743 | }; | ||
| 744 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls); | ||
| 745 | } | ||
| 746 | |||
| 747 | const sh_null: *ElfN.Shdr = @ptrCast(@alignCast(Node.Known.shdr.slice(&elf.mf))); | ||
| 748 | sh_null.* = .{ | ||
| 749 | .name = try elf.string(.shstrtab, ""), | ||
| 750 | .type = std.elf.SHT_NULL, | ||
| 751 | .flags = .{ .shf = .{} }, | ||
| 752 | .addr = 0, | ||
| 753 | .offset = 0, | ||
| 754 | .size = 0, | ||
| 755 | .link = 0, | ||
| 756 | .info = if (phnum >= std.elf.PN_XNUM) phnum else 0, | ||
| 757 | .addralign = 0, | ||
| 758 | .entsize = 0, | ||
| 759 | }; | ||
| 760 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_null); | ||
| 761 | |||
| 762 | try elf.symtab.ensureTotalCapacity(gpa, 1); | ||
| 763 | elf.symtab.addOneAssumeCapacity().* = .{ | ||
| 764 | .ni = .none, | ||
| 765 | .loc_relocs = .none, | ||
| 766 | .target_relocs = .none, | ||
| 767 | .unused = 0, | ||
| 768 | }; | ||
| 769 | assert(try elf.addSection(Node.Known.rodata, .{ | ||
| 770 | .type = std.elf.SHT_SYMTAB, | ||
| 771 | .addralign = addr_align, | ||
| 772 | .entsize = @sizeOf(ElfN.Sym), | ||
| 773 | }) == .symtab); | ||
| 774 | |||
| 775 | const symtab: *ElfN.Sym = @ptrCast(@alignCast(Symbol.Index.symtab.node(elf).slice(&elf.mf))); | ||
| 776 | symtab.* = .{ | ||
| 777 | .name = try elf.string(.strtab, ""), | ||
| 778 | .value = 0, | ||
| 779 | .size = 0, | ||
| 780 | .info = .{ | ||
| 781 | .type = .NOTYPE, | ||
| 782 | .bind = .LOCAL, | ||
| 783 | }, | ||
| 784 | .other = .{ | ||
| 785 | .visibility = .DEFAULT, | ||
| 786 | }, | ||
| 787 | .shndx = std.elf.SHN_UNDEF, | ||
| 788 | }; | ||
| 789 | |||
| 790 | const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class)); | ||
| 791 | ehdr.shstrndx = ehdr.shnum; | ||
| 772 | }, | 792 | }, |
| 773 | .shndx = std.elf.SHN_UNDEF, | ||
| 774 | }; | ||
| 775 | { | ||
| 776 | const ehdr = @field(elf.ehdrPtr(), @tagName(class)); | ||
| 777 | ehdr.shstrndx = ehdr.shnum; | ||
| 778 | } | 793 | } |
| 779 | assert(try elf.addSection(seg_rodata_ni, .{ | 794 | assert(try elf.addSection(Node.Known.rodata, .{ |
| 780 | .type = std.elf.SHT_STRTAB, | 795 | .type = std.elf.SHT_STRTAB, |
| 781 | .addralign = elf.mf.flags.block_size, | 796 | .addralign = elf.mf.flags.block_size, |
| 782 | .entsize = 1, | 797 | .entsize = 1, |
| 783 | }) == .shstrtab); | 798 | }) == .shstrtab); |
| 784 | assert(try elf.addSection(seg_rodata_ni, .{ | 799 | assert(try elf.addSection(Node.Known.rodata, .{ |
| 785 | .type = std.elf.SHT_STRTAB, | 800 | .type = std.elf.SHT_STRTAB, |
| 786 | .addralign = elf.mf.flags.block_size, | 801 | .addralign = elf.mf.flags.block_size, |
| 787 | .entsize = 1, | 802 | .entsize = 1, |
| ... | @@ -793,75 +808,118 @@ fn initHeaders( | ... | @@ -793,75 +808,118 @@ fn initHeaders( |
| 793 | Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[0] = 0; | 808 | Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[0] = 0; |
| 794 | Symbol.Index.strtab.node(elf).slice(&elf.mf)[0] = 0; | 809 | Symbol.Index.strtab.node(elf).slice(&elf.mf)[0] = 0; |
| 795 | 810 | ||
| 796 | assert(try elf.addSection(seg_rodata_ni, .{ | 811 | if (maybe_interp) |interp| { |
| 812 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 813 | const interp_ni = try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{ | ||
| 814 | .size = interp.len + 1, | ||
| 815 | .moved = true, | ||
| 816 | .resized = true, | ||
| 817 | }); | ||
| 818 | elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx }); | ||
| 819 | elf.phdrs.items[interp_phndx] = interp_ni; | ||
| 820 | |||
| 821 | const sec_interp_si = try elf.addSection(interp_ni, .{ | ||
| 822 | .name = ".interp", | ||
| 823 | .size = @intCast(interp.len + 1), | ||
| 824 | .flags = .{ .ALLOC = true }, | ||
| 825 | }); | ||
| 826 | const sec_interp = sec_interp_si.node(elf).slice(&elf.mf); | ||
| 827 | @memcpy(sec_interp[0..interp.len], interp); | ||
| 828 | sec_interp[interp.len] = 0; | ||
| 829 | } | ||
| 830 | assert(try elf.addSection(Node.Known.rodata, .{ | ||
| 797 | .name = ".rodata", | 831 | .name = ".rodata", |
| 798 | .flags = .{ .ALLOC = true }, | 832 | .flags = .{ .ALLOC = true }, |
| 799 | .addralign = elf.mf.flags.block_size, | 833 | .addralign = elf.mf.flags.block_size, |
| 800 | }) == .rodata); | 834 | }) == .rodata); |
| 801 | assert(try elf.addSection(seg_text_ni, .{ | 835 | assert(try elf.addSection(Node.Known.text, .{ |
| 802 | .name = ".text", | 836 | .name = ".text", |
| 803 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, | 837 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, |
| 804 | .addralign = elf.mf.flags.block_size, | 838 | .addralign = elf.mf.flags.block_size, |
| 805 | }) == .text); | 839 | }) == .text); |
| 806 | assert(try elf.addSection(seg_data_ni, .{ | 840 | assert(try elf.addSection(Node.Known.data, .{ |
| 807 | .name = ".data", | 841 | .name = ".data", |
| 808 | .flags = .{ .WRITE = true, .ALLOC = true }, | 842 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 809 | .addralign = elf.mf.flags.block_size, | 843 | .addralign = elf.mf.flags.block_size, |
| 810 | }) == .data); | 844 | }) == .data); |
| 811 | if (comp.config.any_non_single_threaded) { | 845 | if (comp.config.any_non_single_threaded) { |
| 812 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | 846 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 813 | const seg_tls_ni = try elf.mf.addLastChildNode(gpa, seg_data_ni, .{ | 847 | elf.known.tls = try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{ |
| 814 | .alignment = elf.mf.flags.block_size, | 848 | .alignment = elf.mf.flags.block_size, |
| 815 | .moved = true, | 849 | .moved = true, |
| 816 | }); | 850 | }); |
| 817 | elf.nodes.appendAssumeCapacity(.{ .segment = tls_phndx }); | 851 | elf.nodes.appendAssumeCapacity(.{ .segment = tls_phndx }); |
| 852 | elf.phdrs.items[tls_phndx] = elf.known.tls; | ||
| 818 | 853 | ||
| 819 | assert(try elf.addSection(seg_tls_ni, .{ | 854 | assert(try elf.addSection(elf.known.tls, .{ |
| 820 | .name = ".tdata", | 855 | .name = ".tdata", |
| 821 | .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true }, | 856 | .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true }, |
| 822 | .addralign = elf.mf.flags.block_size, | 857 | .addralign = elf.mf.flags.block_size, |
| 823 | }) == .tdata); | 858 | }) == .tdata); |
| 824 | } | 859 | } |
| 825 | if (maybe_interp) |interp| { | 860 | assert(elf.nodes.len == expected_nodes_len); |
| 826 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 827 | const seg_interp_ni = try elf.mf.addLastChildNode(gpa, seg_rodata_ni, .{ | ||
| 828 | .size = interp.len + 1, | ||
| 829 | .moved = true, | ||
| 830 | .resized = true, | ||
| 831 | }); | ||
| 832 | elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx }); | ||
| 833 | |||
| 834 | const sec_interp_si = try elf.addSection(seg_interp_ni, .{ | ||
| 835 | .name = ".interp", | ||
| 836 | .size = @intCast(interp.len + 1), | ||
| 837 | .flags = .{ .ALLOC = true }, | ||
| 838 | }); | ||
| 839 | const sec_interp = sec_interp_si.node(elf).slice(&elf.mf); | ||
| 840 | @memcpy(sec_interp[0..interp.len], interp); | ||
| 841 | sec_interp[interp.len] = 0; | ||
| 842 | } | ||
| 843 | } | 861 | } |
| 844 | 862 | ||
| 845 | fn getNode(elf: *Elf, ni: MappedFile.Node.Index) Node { | 863 | fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node { |
| 846 | return elf.nodes.get(@intFromEnum(ni)); | 864 | return elf.nodes.get(@intFromEnum(ni)); |
| 847 | } | 865 | } |
| 866 | fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { | ||
| 867 | const parent_vaddr = parent_vaddr: { | ||
| 868 | const parent_si = switch (elf.getNode(ni.parent(&elf.mf))) { | ||
| 869 | .file, .ehdr, .shdr => unreachable, | ||
| 870 | .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) { | ||
| 871 | inline else => |ph| elf.targetLoad(&ph[phndx].vaddr), | ||
| 872 | }, | ||
| 873 | .section => |si| si, | ||
| 874 | inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf), | ||
| 875 | }; | ||
| 876 | break :parent_vaddr switch (elf.symPtr(parent_si)) { | ||
| 877 | inline else => |sym| elf.targetLoad(&sym.value), | ||
| 878 | }; | ||
| 879 | }; | ||
| 880 | const offset, _ = ni.location(&elf.mf).resolve(&elf.mf); | ||
| 881 | return parent_vaddr + offset; | ||
| 882 | } | ||
| 848 | 883 | ||
| 849 | pub fn identClass(elf: *Elf) std.elf.CLASS { | 884 | pub fn identClass(elf: *const Elf) std.elf.CLASS { |
| 850 | return @enumFromInt(elf.mf.contents[std.elf.EI.CLASS]); | 885 | return @enumFromInt(elf.mf.contents[std.elf.EI.CLASS]); |
| 851 | } | 886 | } |
| 852 | 887 | pub fn identData(elf: *const Elf) std.elf.DATA { | |
| 853 | pub fn identData(elf: *Elf) std.elf.DATA { | ||
| 854 | return @enumFromInt(elf.mf.contents[std.elf.EI.DATA]); | 888 | return @enumFromInt(elf.mf.contents[std.elf.EI.DATA]); |
| 855 | } | 889 | } |
| 856 | fn endianForData(data: std.elf.DATA) std.builtin.Endian { | 890 | |
| 857 | return switch (data) { | 891 | pub fn targetEndian(elf: *const Elf) std.builtin.Endian { |
| 892 | return switch (elf.identData()) { | ||
| 858 | .NONE, _ => unreachable, | 893 | .NONE, _ => unreachable, |
| 859 | .@"2LSB" => .little, | 894 | .@"2LSB" => .little, |
| 860 | .@"2MSB" => .big, | 895 | .@"2MSB" => .big, |
| 861 | }; | 896 | }; |
| 862 | } | 897 | } |
| 863 | pub fn targetEndian(elf: *Elf) std.builtin.Endian { | 898 | fn targetLoad(elf: *const Elf, ptr: anytype) @typeInfo(@TypeOf(ptr)).pointer.child { |
| 864 | return endianForData(elf.identData()); | 899 | const Child = @typeInfo(@TypeOf(ptr)).pointer.child; |
| 900 | return switch (@typeInfo(Child)) { | ||
| 901 | else => @compileError(@typeName(Child)), | ||
| 902 | .int => std.mem.toNative(Child, ptr.*, elf.targetEndian()), | ||
| 903 | .@"enum" => |@"enum"| @enumFromInt(elf.targetLoad(@as(*@"enum".tag_type, @ptrCast(ptr)))), | ||
| 904 | .@"struct" => |@"struct"| @bitCast( | ||
| 905 | elf.targetLoad(@as(*@"struct".backing_integer.?, @ptrCast(ptr))), | ||
| 906 | ), | ||
| 907 | }; | ||
| 908 | } | ||
| 909 | fn targetStore(elf: *const Elf, ptr: anytype, val: @typeInfo(@TypeOf(ptr)).pointer.child) void { | ||
| 910 | const Child = @typeInfo(@TypeOf(ptr)).pointer.child; | ||
| 911 | return switch (@typeInfo(Child)) { | ||
| 912 | else => @compileError(@typeName(Child)), | ||
| 913 | .int => ptr.* = std.mem.nativeTo(Child, val, elf.targetEndian()), | ||
| 914 | .@"enum" => |@"enum"| elf.targetStore( | ||
| 915 | @as(*@"enum".tag_type, @ptrCast(ptr)), | ||
| 916 | @intFromEnum(val), | ||
| 917 | ), | ||
| 918 | .@"struct" => |@"struct"| elf.targetStore( | ||
| 919 | @as(*@"struct".backing_integer.?, @ptrCast(ptr)), | ||
| 920 | @bitCast(val), | ||
| 921 | ), | ||
| 922 | }; | ||
| 865 | } | 923 | } |
| 866 | 924 | ||
| 867 | pub const EhdrPtr = union(std.elf.CLASS) { | 925 | pub const EhdrPtr = union(std.elf.CLASS) { |
| ... | @@ -870,7 +928,7 @@ pub const EhdrPtr = union(std.elf.CLASS) { | ... | @@ -870,7 +928,7 @@ pub const EhdrPtr = union(std.elf.CLASS) { |
| 870 | @"64": *std.elf.Elf64.Ehdr, | 928 | @"64": *std.elf.Elf64.Ehdr, |
| 871 | }; | 929 | }; |
| 872 | pub fn ehdrPtr(elf: *Elf) EhdrPtr { | 930 | pub fn ehdrPtr(elf: *Elf) EhdrPtr { |
| 873 | const slice = Node.known.ehdr.slice(&elf.mf); | 931 | const slice = Node.Known.ehdr.slice(&elf.mf); |
| 874 | return switch (elf.identClass()) { | 932 | return switch (elf.identClass()) { |
| 875 | .NONE, _ => unreachable, | 933 | .NONE, _ => unreachable, |
| 876 | inline else => |class| @unionInit( | 934 | inline else => |class| @unionInit( |
| ... | @@ -882,26 +940,12 @@ pub fn ehdrPtr(elf: *Elf) EhdrPtr { | ... | @@ -882,26 +940,12 @@ pub fn ehdrPtr(elf: *Elf) EhdrPtr { |
| 882 | } | 940 | } |
| 883 | pub fn ehdrField( | 941 | pub fn ehdrField( |
| 884 | elf: *Elf, | 942 | elf: *Elf, |
| 885 | comptime field: enum { type, machine }, | 943 | comptime field: std.meta.FieldEnum(std.elf.Elf64.Ehdr), |
| 886 | ) @FieldType(std.elf.Elf32.Ehdr, @tagName(field)) { | 944 | ) @FieldType(std.elf.Elf64.Ehdr, @tagName(field)) { |
| 887 | return @enumFromInt(std.mem.toNative( | 945 | return switch (elf.ehdrPtr()) { |
| 888 | @typeInfo(@FieldType(std.elf.Elf32.Ehdr, @tagName(field))).@"enum".tag_type, | 946 | inline else => |ehdr| elf.targetLoad(&@field(ehdr, @tagName(field))), |
| 889 | @intFromEnum(switch (elf.ehdrPtr()) { | ||
| 890 | inline else => |ehdr| @field(ehdr, @tagName(field)), | ||
| 891 | }), | ||
| 892 | elf.targetEndian(), | ||
| 893 | )); | ||
| 894 | } | ||
| 895 | |||
| 896 | fn baseAddrForType(@"type": std.elf.ET) u64 { | ||
| 897 | return switch (@"type") { | ||
| 898 | else => 0, | ||
| 899 | .EXEC => 0x1000000, | ||
| 900 | }; | 947 | }; |
| 901 | } | 948 | } |
| 902 | pub fn baseAddr(elf: *Elf) u64 { | ||
| 903 | return baseAddrForType(elf.ehdrField(.type)); | ||
| 904 | } | ||
| 905 | 949 | ||
| 906 | pub const PhdrSlice = union(std.elf.CLASS) { | 950 | pub const PhdrSlice = union(std.elf.CLASS) { |
| 907 | NONE: noreturn, | 951 | NONE: noreturn, |
| ... | @@ -909,7 +953,7 @@ pub const PhdrSlice = union(std.elf.CLASS) { | ... | @@ -909,7 +953,7 @@ pub const PhdrSlice = union(std.elf.CLASS) { |
| 909 | @"64": []std.elf.Elf64.Phdr, | 953 | @"64": []std.elf.Elf64.Phdr, |
| 910 | }; | 954 | }; |
| 911 | pub fn phdrSlice(elf: *Elf) PhdrSlice { | 955 | pub fn phdrSlice(elf: *Elf) PhdrSlice { |
| 912 | const slice = Node.known.phdr.slice(&elf.mf); | 956 | const slice = Node.Known.phdr.slice(&elf.mf); |
| 913 | return switch (elf.identClass()) { | 957 | return switch (elf.identClass()) { |
| 914 | .NONE, _ => unreachable, | 958 | .NONE, _ => unreachable, |
| 915 | inline else => |class| @unionInit( | 959 | inline else => |class| @unionInit( |
| ... | @@ -926,7 +970,7 @@ pub const ShdrSlice = union(std.elf.CLASS) { | ... | @@ -926,7 +970,7 @@ pub const ShdrSlice = union(std.elf.CLASS) { |
| 926 | @"64": []std.elf.Elf64.Shdr, | 970 | @"64": []std.elf.Elf64.Shdr, |
| 927 | }; | 971 | }; |
| 928 | pub fn shdrSlice(elf: *Elf) ShdrSlice { | 972 | pub fn shdrSlice(elf: *Elf) ShdrSlice { |
| 929 | const slice = Node.known.shdr.slice(&elf.mf); | 973 | const slice = Node.Known.shdr.slice(&elf.mf); |
| 930 | return switch (elf.identClass()) { | 974 | return switch (elf.identClass()) { |
| 931 | .NONE, _ => unreachable, | 975 | .NONE, _ => unreachable, |
| 932 | inline else => |class| @unionInit( | 976 | inline else => |class| @unionInit( |
| ... | @@ -937,17 +981,17 @@ pub fn shdrSlice(elf: *Elf) ShdrSlice { | ... | @@ -937,17 +981,17 @@ pub fn shdrSlice(elf: *Elf) ShdrSlice { |
| 937 | }; | 981 | }; |
| 938 | } | 982 | } |
| 939 | 983 | ||
| 940 | pub const SymSlice = union(std.elf.CLASS) { | 984 | pub const SymtabSlice = union(std.elf.CLASS) { |
| 941 | NONE: noreturn, | 985 | NONE: noreturn, |
| 942 | @"32": []std.elf.Elf32.Sym, | 986 | @"32": []std.elf.Elf32.Sym, |
| 943 | @"64": []std.elf.Elf64.Sym, | 987 | @"64": []std.elf.Elf64.Sym, |
| 944 | }; | 988 | }; |
| 945 | pub fn symSlice(elf: *Elf) SymSlice { | 989 | pub fn symtabSlice(elf: *Elf) SymtabSlice { |
| 946 | const slice = Symbol.Index.symtab.node(elf).slice(&elf.mf); | 990 | const slice = Symbol.Index.symtab.node(elf).slice(&elf.mf); |
| 947 | return switch (elf.identClass()) { | 991 | return switch (elf.identClass()) { |
| 948 | .NONE, _ => unreachable, | 992 | .NONE, _ => unreachable, |
| 949 | inline else => |class| @unionInit( | 993 | inline else => |class| @unionInit( |
| 950 | SymSlice, | 994 | SymtabSlice, |
| 951 | @tagName(class), | 995 | @tagName(class), |
| 952 | @ptrCast(@alignCast(slice)), | 996 | @ptrCast(@alignCast(slice)), |
| 953 | ), | 997 | ), |
| ... | @@ -960,7 +1004,7 @@ pub const SymPtr = union(std.elf.CLASS) { | ... | @@ -960,7 +1004,7 @@ pub const SymPtr = union(std.elf.CLASS) { |
| 960 | @"64": *std.elf.Elf64.Sym, | 1004 | @"64": *std.elf.Elf64.Sym, |
| 961 | }; | 1005 | }; |
| 962 | pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr { | 1006 | pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr { |
| 963 | return switch (elf.symSlice()) { | 1007 | return switch (elf.symtabSlice()) { |
| 964 | inline else => |sym, class| @unionInit(SymPtr, @tagName(class), &sym[@intFromEnum(si)]), | 1008 | inline else => |sym, class| @unionInit(SymPtr, @tagName(class), &sym[@intFromEnum(si)]), |
| 965 | }; | 1009 | }; |
| 966 | } | 1010 | } |
| ... | @@ -1123,7 +1167,9 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In | ... | @@ -1123,7 +1167,9 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In |
| 1123 | } }, | 1167 | } }, |
| 1124 | }, | 1168 | }, |
| 1125 | ); | 1169 | ); |
| 1126 | return 0; | 1170 | return switch (elf.symPtr(target_si)) { |
| 1171 | inline else => |sym| elf.targetLoad(&sym.value), | ||
| 1172 | }; | ||
| 1127 | } | 1173 | } |
| 1128 | 1174 | ||
| 1129 | fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | 1175 | fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| ... | @@ -1135,21 +1181,19 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | ... | @@ -1135,21 +1181,19 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 1135 | entsize: std.elf.Word = 0, | 1181 | entsize: std.elf.Word = 0, |
| 1136 | }) !Symbol.Index { | 1182 | }) !Symbol.Index { |
| 1137 | const gpa = elf.base.comp.gpa; | 1183 | const gpa = elf.base.comp.gpa; |
| 1138 | const target_endian = elf.targetEndian(); | ||
| 1139 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | 1184 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 1140 | try elf.symtab.ensureUnusedCapacity(gpa, 1); | 1185 | try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| 1141 | 1186 | ||
| 1142 | const shstrtab_entry = try elf.string(.shstrtab, opts.name); | 1187 | const shstrtab_entry = try elf.string(.shstrtab, opts.name); |
| 1143 | const shndx, const shdr_size = shndx: switch (elf.ehdrPtr()) { | 1188 | const shndx, const shdr_size = shndx: switch (elf.ehdrPtr()) { |
| 1144 | inline else => |ehdr| { | 1189 | inline else => |ehdr| { |
| 1145 | const shentsize = std.mem.toNative(@TypeOf(ehdr.shentsize), ehdr.shentsize, target_endian); | 1190 | const shndx = elf.targetLoad(&ehdr.shnum); |
| 1146 | const shndx = std.mem.toNative(@TypeOf(ehdr.shnum), ehdr.shnum, target_endian); | ||
| 1147 | const shnum = shndx + 1; | 1191 | const shnum = shndx + 1; |
| 1148 | ehdr.shnum = std.mem.nativeTo(@TypeOf(ehdr.shnum), shnum, target_endian); | 1192 | elf.targetStore(&ehdr.shnum, shnum); |
| 1149 | break :shndx .{ shndx, shentsize * shnum }; | 1193 | break :shndx .{ shndx, elf.targetLoad(&ehdr.shentsize) * shnum }; |
| 1150 | }, | 1194 | }, |
| 1151 | }; | 1195 | }; |
| 1152 | try Node.known.shdr.resize(&elf.mf, gpa, shdr_size); | 1196 | try Node.Known.shdr.resize(&elf.mf, gpa, shdr_size); |
| 1153 | const ni = try elf.mf.addLastChildNode(gpa, segment_ni, .{ | 1197 | const ni = try elf.mf.addLastChildNode(gpa, segment_ni, .{ |
| 1154 | .alignment = opts.addralign, | 1198 | .alignment = opts.addralign, |
| 1155 | .size = opts.size, | 1199 | .size = opts.size, |
| ... | @@ -1179,7 +1223,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | ... | @@ -1179,7 +1223,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 1179 | .addralign = @intCast(opts.addralign.toByteUnits()), | 1223 | .addralign = @intCast(opts.addralign.toByteUnits()), |
| 1180 | .entsize = opts.entsize, | 1224 | .entsize = opts.entsize, |
| 1181 | }; | 1225 | }; |
| 1182 | if (target_endian != native_endian) std.mem.byteSwapAllFields(@TypeOf(sh.*), sh); | 1226 | if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(@TypeOf(sh.*), sh); |
| 1183 | }, | 1227 | }, |
| 1184 | } | 1228 | } |
| 1185 | return si; | 1229 | return si; |
| ... | @@ -1188,37 +1232,29 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | ... | @@ -1188,37 +1232,29 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 1188 | fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void { | 1232 | fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void { |
| 1189 | const strtab_entry = try elf.string(.strtab, name); | 1233 | const strtab_entry = try elf.string(.strtab, name); |
| 1190 | const shstrtab_entry = try elf.string(.shstrtab, name); | 1234 | const shstrtab_entry = try elf.string(.shstrtab, name); |
| 1191 | const target_endian = elf.targetEndian(); | ||
| 1192 | switch (elf.shdrSlice()) { | 1235 | switch (elf.shdrSlice()) { |
| 1193 | inline else => |shdr, class| { | 1236 | inline else => |shdr, class| { |
| 1194 | const sym = @field(elf.symPtr(si), @tagName(class)); | 1237 | const sym = @field(elf.symPtr(si), @tagName(class)); |
| 1195 | sym.name = std.mem.nativeTo(@TypeOf(sym.name), strtab_entry, target_endian); | 1238 | elf.targetStore(&sym.name, strtab_entry); |
| 1196 | const shndx = std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian); | 1239 | const sh = &shdr[elf.targetLoad(&sym.shndx)]; |
| 1197 | const sh = &shdr[shndx]; | 1240 | elf.targetStore(&sh.name, shstrtab_entry); |
| 1198 | sh.name = std.mem.nativeTo(@TypeOf(sh.name), shstrtab_entry, target_endian); | ||
| 1199 | }, | 1241 | }, |
| 1200 | } | 1242 | } |
| 1201 | } | 1243 | } |
| 1202 | 1244 | ||
| 1203 | fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void { | 1245 | fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void { |
| 1204 | const target_endian = elf.targetEndian(); | ||
| 1205 | switch (elf.shdrSlice()) { | 1246 | switch (elf.shdrSlice()) { |
| 1206 | inline else => |shdr, class| { | 1247 | inline else => |shdr, class| shdr[ |
| 1207 | const sym = @field(elf.symPtr(si), @tagName(class)); | 1248 | elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx) |
| 1208 | const shndx = std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian); | 1249 | ].link = @field(elf.symPtr(link_si), @tagName(class)).shndx, |
| 1209 | shdr[shndx].link = @field(elf.symPtr(link_si), @tagName(class)).shndx; | ||
| 1210 | }, | ||
| 1211 | } | 1250 | } |
| 1212 | } | 1251 | } |
| 1213 | 1252 | ||
| 1214 | fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 { | 1253 | fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 { |
| 1215 | const target_endian = elf.targetEndian(); | 1254 | const name = Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrSlice()) { |
| 1216 | const name = Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[name: switch (elf.shdrSlice()) { | 1255 | inline else => |shndx, class| elf.targetLoad( |
| 1217 | inline else => |shndx, class| { | 1256 | &shndx[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name, |
| 1218 | const sym = @field(elf.symPtr(si), @tagName(class)); | 1257 | ), |
| 1219 | const sh = &shndx[std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian)]; | ||
| 1220 | break :name std.mem.toNative(@TypeOf(sh.name), sh.name, target_endian); | ||
| 1221 | }, | ||
| 1222 | }..]; | 1258 | }..]; |
| 1223 | return name[0..std.mem.indexOfScalar(u8, name, 0).? :0]; | 1259 | return name[0..std.mem.indexOfScalar(u8, name, 0).? :0]; |
| 1224 | } | 1260 | } |
| ... | @@ -1243,7 +1279,7 @@ pub fn addReloc( | ... | @@ -1243,7 +1279,7 @@ pub fn addReloc( |
| 1243 | ) !void { | 1279 | ) !void { |
| 1244 | const gpa = elf.base.comp.gpa; | 1280 | const gpa = elf.base.comp.gpa; |
| 1245 | const target = target_si.get(elf); | 1281 | const target = target_si.get(elf); |
| 1246 | const ri: link.File.Elf2.Reloc.Index = @enumFromInt(elf.relocs.items.len); | 1282 | const ri: Reloc.Index = @enumFromInt(elf.relocs.items.len); |
| 1247 | (try elf.relocs.addOne(gpa)).* = .{ | 1283 | (try elf.relocs.addOne(gpa)).* = .{ |
| 1248 | .type = @"type", | 1284 | .type = @"type", |
| 1249 | .prev = .none, | 1285 | .prev = .none, |
| ... | @@ -1332,10 +1368,8 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) | ... | @@ -1332,10 +1368,8 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) |
| 1332 | error.WriteFailed => return error.OutOfMemory, | 1368 | error.WriteFailed => return error.OutOfMemory, |
| 1333 | else => |e| return e, | 1369 | else => |e| return e, |
| 1334 | }; | 1370 | }; |
| 1335 | const target_endian = elf.targetEndian(); | ||
| 1336 | switch (elf.symPtr(si)) { | 1371 | switch (elf.symPtr(si)) { |
| 1337 | inline else => |sym| sym.size = | 1372 | inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)), |
| 1338 | std.mem.nativeTo(@TypeOf(sym.size), @intCast(nw.interface.end), target_endian), | ||
| 1339 | } | 1373 | } |
| 1340 | si.applyLocationRelocs(elf); | 1374 | si.applyLocationRelocs(elf); |
| 1341 | } | 1375 | } |
| ... | @@ -1463,10 +1497,8 @@ fn updateFuncInner( | ... | @@ -1463,10 +1497,8 @@ fn updateFuncInner( |
| 1463 | error.WriteFailed => return nw.err.?, | 1497 | error.WriteFailed => return nw.err.?, |
| 1464 | else => |e| return e, | 1498 | else => |e| return e, |
| 1465 | }; | 1499 | }; |
| 1466 | const target_endian = elf.targetEndian(); | ||
| 1467 | switch (elf.symPtr(si)) { | 1500 | switch (elf.symPtr(si)) { |
| 1468 | inline else => |sym| sym.size = | 1501 | inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)), |
| 1469 | std.mem.nativeTo(@TypeOf(sym.size), @intCast(nw.interface.end), target_endian), | ||
| 1470 | } | 1502 | } |
| 1471 | si.applyLocationRelocs(elf); | 1503 | si.applyLocationRelocs(elf); |
| 1472 | } | 1504 | } |
| ... | @@ -1634,10 +1666,8 @@ fn flushUav( | ... | @@ -1634,10 +1666,8 @@ fn flushUav( |
| 1634 | error.WriteFailed => return error.OutOfMemory, | 1666 | error.WriteFailed => return error.OutOfMemory, |
| 1635 | else => |e| return e, | 1667 | else => |e| return e, |
| 1636 | }; | 1668 | }; |
| 1637 | const target_endian = elf.targetEndian(); | ||
| 1638 | switch (elf.symPtr(si)) { | 1669 | switch (elf.symPtr(si)) { |
| 1639 | inline else => |sym| sym.size = | 1670 | inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)), |
| 1640 | std.mem.nativeTo(@TypeOf(sym.size), @intCast(nw.interface.end), target_endian), | ||
| 1641 | } | 1671 | } |
| 1642 | si.applyLocationRelocs(elf); | 1672 | si.applyLocationRelocs(elf); |
| 1643 | } | 1673 | } |
| ... | @@ -1689,167 +1719,121 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { | ... | @@ -1689,167 +1719,121 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { |
| 1689 | .none, | 1719 | .none, |
| 1690 | .{ .atom_index = @intFromEnum(si) }, | 1720 | .{ .atom_index = @intFromEnum(si) }, |
| 1691 | ); | 1721 | ); |
| 1692 | const target_endian = elf.targetEndian(); | ||
| 1693 | switch (elf.symPtr(si)) { | 1722 | switch (elf.symPtr(si)) { |
| 1694 | inline else => |sym| sym.size = | 1723 | inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)), |
| 1695 | std.mem.nativeTo(@TypeOf(sym.size), @intCast(nw.interface.end), target_endian), | ||
| 1696 | } | 1724 | } |
| 1697 | si.applyLocationRelocs(elf); | 1725 | si.applyLocationRelocs(elf); |
| 1698 | } | 1726 | } |
| 1699 | 1727 | ||
| 1700 | fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { | 1728 | fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 1701 | const target_endian = elf.targetEndian(); | 1729 | switch (elf.getNode(ni)) { |
| 1702 | const file_offset = ni.fileLocation(&elf.mf, false).offset; | 1730 | .file => unreachable, |
| 1703 | const node = elf.getNode(ni); | 1731 | .ehdr => assert(ni.fileLocation(&elf.mf, false).offset == 0), |
| 1704 | switch (node) { | ||
| 1705 | else => |tag| @panic(@tagName(tag)), | ||
| 1706 | .ehdr => assert(file_offset == 0), | ||
| 1707 | .shdr => switch (elf.ehdrPtr()) { | 1732 | .shdr => switch (elf.ehdrPtr()) { |
| 1708 | inline else => |ehdr| ehdr.shoff = | 1733 | inline else => |ehdr| elf.targetStore( |
| 1709 | std.mem.nativeTo(@TypeOf(ehdr.shoff), @intCast(file_offset), target_endian), | 1734 | &ehdr.shoff, |
| 1735 | @intCast(ni.fileLocation(&elf.mf, false).offset), | ||
| 1736 | ), | ||
| 1710 | }, | 1737 | }, |
| 1711 | .segment => |phndx| switch (elf.phdrSlice()) { | 1738 | .segment => |phndx| switch (elf.phdrSlice()) { |
| 1712 | inline else => |phdr, class| { | 1739 | inline else => |phdr, class| { |
| 1713 | const ph = &phdr[phndx]; | 1740 | const ph = &phdr[phndx]; |
| 1714 | switch (std.mem.toNative(@TypeOf(ph.type), ph.type, target_endian)) { | 1741 | elf.targetStore(&ph.offset, @intCast(ni.fileLocation(&elf.mf, false).offset)); |
| 1742 | switch (elf.targetLoad(&ph.type)) { | ||
| 1715 | else => unreachable, | 1743 | else => unreachable, |
| 1716 | std.elf.PT_NULL, std.elf.PT_LOAD, std.elf.PT_DYNAMIC, std.elf.PT_INTERP => {}, | 1744 | std.elf.PT_NULL, std.elf.PT_LOAD => return, |
| 1717 | std.elf.PT_PHDR => { | 1745 | std.elf.PT_DYNAMIC, std.elf.PT_INTERP => {}, |
| 1718 | const ehdr = @field(elf.ehdrPtr(), @tagName(class)); | 1746 | std.elf.PT_PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset, |
| 1719 | ehdr.phoff = | ||
| 1720 | std.mem.nativeTo(@TypeOf(ehdr.phoff), @intCast(file_offset), target_endian); | ||
| 1721 | }, | ||
| 1722 | std.elf.PT_TLS => {}, | 1747 | std.elf.PT_TLS => {}, |
| 1723 | } | 1748 | } |
| 1724 | ph.offset = std.mem.nativeTo(@TypeOf(ph.offset), @intCast(file_offset), target_endian); | 1749 | elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni))); |
| 1725 | ph.vaddr = std.mem.nativeTo( | ||
| 1726 | @TypeOf(ph.vaddr), | ||
| 1727 | @intCast(elf.baseAddr() + file_offset), | ||
| 1728 | target_endian, | ||
| 1729 | ); | ||
| 1730 | ph.paddr = ph.vaddr; | 1750 | ph.paddr = ph.vaddr; |
| 1731 | }, | 1751 | }, |
| 1732 | }, | 1752 | }, |
| 1733 | .section => |si| switch (elf.shdrSlice()) { | 1753 | .section => |si| switch (elf.shdrSlice()) { |
| 1734 | inline else => |shdr, class| { | 1754 | inline else => |shdr, class| { |
| 1735 | const sym = @field(elf.symPtr(si), @tagName(class)); | 1755 | const sym = @field(elf.symPtr(si), @tagName(class)); |
| 1736 | const shndx = std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian); | 1756 | const sh = &shdr[elf.targetLoad(&sym.shndx)]; |
| 1737 | const sh = &shdr[shndx]; | 1757 | elf.targetStore(&sh.offset, @intCast(ni.fileLocation(&elf.mf, false).offset)); |
| 1738 | const flags: @TypeOf(sh.flags) = @bitCast(std.mem.toNative( | 1758 | const flags = elf.targetLoad(&sh.flags).shf; |
| 1739 | @typeInfo(@TypeOf(sh.flags)).@"struct".backing_integer.?, | 1759 | if (flags.ALLOC) { |
| 1740 | @bitCast(sh.flags), | 1760 | elf.targetStore(&sh.addr, @intCast(elf.computeNodeVAddr(ni))); |
| 1741 | target_endian, | 1761 | if (!flags.TLS) sym.value = sh.addr; |
| 1742 | )); | ||
| 1743 | if (flags.shf.ALLOC) { | ||
| 1744 | sym.value = std.mem.nativeTo( | ||
| 1745 | @TypeOf(sym.value), | ||
| 1746 | @intCast(elf.baseAddr() + file_offset), | ||
| 1747 | target_endian, | ||
| 1748 | ); | ||
| 1749 | sh.addr = sym.value; | ||
| 1750 | } | 1762 | } |
| 1751 | sh.offset = std.mem.nativeTo(@TypeOf(sh.offset), @intCast(file_offset), target_endian); | ||
| 1752 | }, | 1763 | }, |
| 1753 | }, | 1764 | }, |
| 1754 | .nav, .uav, .lazy_code, .lazy_const_data => { | 1765 | inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf).flushMoved(elf), |
| 1755 | const si = switch (node) { | ||
| 1756 | else => unreachable, | ||
| 1757 | inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf), | ||
| 1758 | }; | ||
| 1759 | switch (elf.shdrSlice()) { | ||
| 1760 | inline else => |shdr, class| { | ||
| 1761 | const sym = @field(elf.symPtr(si), @tagName(class)); | ||
| 1762 | const sh = &shdr[std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian)]; | ||
| 1763 | const flags: @TypeOf(sh.flags) = @bitCast(std.mem.toNative( | ||
| 1764 | @typeInfo(@TypeOf(sh.flags)).@"struct".backing_integer.?, | ||
| 1765 | @bitCast(sh.flags), | ||
| 1766 | target_endian, | ||
| 1767 | )); | ||
| 1768 | const sh_addr = if (flags.shf.TLS) | ||
| 1769 | 0 | ||
| 1770 | else | ||
| 1771 | std.mem.toNative(@TypeOf(sh.addr), sh.addr, target_endian); | ||
| 1772 | const sh_offset = std.mem.toNative(@TypeOf(sh.offset), sh.offset, target_endian); | ||
| 1773 | sym.value = std.mem.nativeTo( | ||
| 1774 | @TypeOf(sym.value), | ||
| 1775 | @intCast(file_offset - sh_offset + sh_addr), | ||
| 1776 | target_endian, | ||
| 1777 | ); | ||
| 1778 | if (si == elf.entry_hack) @field(elf.ehdrPtr(), @tagName(class)).entry = sym.value; | ||
| 1779 | }, | ||
| 1780 | } | ||
| 1781 | si.applyLocationRelocs(elf); | ||
| 1782 | si.applyTargetRelocs(elf); | ||
| 1783 | }, | ||
| 1784 | } | 1766 | } |
| 1785 | try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); | 1767 | try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); |
| 1786 | } | 1768 | } |
| 1787 | 1769 | ||
| 1788 | fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { | 1770 | fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 1789 | const target_endian = elf.targetEndian(); | ||
| 1790 | _, const size = ni.location(&elf.mf).resolve(&elf.mf); | 1771 | _, const size = ni.location(&elf.mf).resolve(&elf.mf); |
| 1791 | const node = elf.getNode(ni); | 1772 | switch (elf.getNode(ni)) { |
| 1792 | switch (node) { | 1773 | .file => {}, |
| 1793 | else => |tag| @panic(@tagName(tag)), | 1774 | .ehdr => unreachable, |
| 1794 | .file, .shdr => {}, | 1775 | .shdr => {}, |
| 1795 | .segment => |phndx| switch (elf.phdrSlice()) { | 1776 | .segment => |phndx| switch (elf.phdrSlice()) { |
| 1796 | inline else => |phdr| { | 1777 | inline else => |phdr| { |
| 1778 | assert(elf.phdrs.items[phndx] == ni); | ||
| 1797 | const ph = &phdr[phndx]; | 1779 | const ph = &phdr[phndx]; |
| 1798 | ph.filesz = std.mem.nativeTo(@TypeOf(ph.filesz), @intCast(size), target_endian); | 1780 | elf.targetStore(&ph.filesz, @intCast(size)); |
| 1799 | ph.memsz = ph.filesz; | 1781 | if (size > elf.targetLoad(&ph.memsz)) { |
| 1800 | switch (std.mem.toNative(@TypeOf(ph.type), ph.type, target_endian)) { | 1782 | const memsz = ni.alignment(&elf.mf).forward(@intCast(size * 4)); |
| 1801 | else => unreachable, | 1783 | elf.targetStore(&ph.memsz, @intCast(memsz)); |
| 1802 | std.elf.PT_NULL => { | 1784 | switch (elf.targetLoad(&ph.type)) { |
| 1803 | if (size > 0) ph.type = std.mem.nativeTo( | 1785 | else => unreachable, |
| 1804 | @TypeOf(ph.type), | 1786 | std.elf.PT_NULL => if (size > 0) elf.targetStore(&ph.type, std.elf.PT_LOAD), |
| 1805 | std.elf.PT_LOAD, | 1787 | std.elf.PT_LOAD => if (size == 0) elf.targetStore(&ph.type, std.elf.PT_NULL), |
| 1806 | target_endian, | 1788 | std.elf.PT_DYNAMIC, std.elf.PT_INTERP, std.elf.PT_PHDR => return, |
| 1807 | ); | 1789 | std.elf.PT_TLS => return ni.childrenMoved(elf.base.comp.gpa, &elf.mf), |
| 1808 | }, | 1790 | } |
| 1809 | std.elf.PT_LOAD => { | 1791 | var vaddr = elf.targetLoad(&ph.vaddr); |
| 1810 | if (size == 0) ph.type = std.mem.nativeTo( | 1792 | var new_phndx = phndx; |
| 1811 | @TypeOf(ph.type), | 1793 | for (phdr[phndx + 1 ..], phndx + 1..) |*next_ph, next_phndx| { |
| 1812 | std.elf.PT_NULL, | 1794 | switch (elf.targetLoad(&next_ph.type)) { |
| 1813 | target_endian, | 1795 | else => unreachable, |
| 1814 | ); | 1796 | std.elf.PT_NULL, std.elf.PT_LOAD => {}, |
| 1815 | }, | 1797 | std.elf.PT_DYNAMIC, |
| 1816 | std.elf.PT_DYNAMIC, std.elf.PT_INTERP, std.elf.PT_PHDR => {}, | 1798 | std.elf.PT_INTERP, |
| 1817 | std.elf.PT_TLS => try ni.childrenMoved(elf.base.comp.gpa, &elf.mf), | 1799 | std.elf.PT_PHDR, |
| 1800 | std.elf.PT_TLS, | ||
| 1801 | => break, | ||
| 1802 | } | ||
| 1803 | const next_vaddr = elf.targetLoad(&next_ph.vaddr); | ||
| 1804 | if (vaddr + memsz <= next_vaddr) break; | ||
| 1805 | vaddr = next_vaddr + elf.targetLoad(&next_ph.memsz); | ||
| 1806 | std.mem.swap(@TypeOf(ph.*), &phdr[new_phndx], next_ph); | ||
| 1807 | const next_ni = elf.phdrs.items[next_phndx]; | ||
| 1808 | elf.phdrs.items[new_phndx] = next_ni; | ||
| 1809 | elf.nodes.items(.data)[@intFromEnum(next_ni)] = .{ .segment = new_phndx }; | ||
| 1810 | new_phndx = @intCast(next_phndx); | ||
| 1811 | } | ||
| 1812 | if (new_phndx != phndx) { | ||
| 1813 | const new_ph = &phdr[new_phndx]; | ||
| 1814 | elf.targetStore(&new_ph.vaddr, vaddr); | ||
| 1815 | new_ph.paddr = new_ph.vaddr; | ||
| 1816 | elf.phdrs.items[new_phndx] = ni; | ||
| 1817 | elf.nodes.items(.data)[@intFromEnum(ni)] = .{ .segment = new_phndx }; | ||
| 1818 | try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); | ||
| 1819 | } | ||
| 1818 | } | 1820 | } |
| 1819 | }, | 1821 | }, |
| 1820 | }, | 1822 | }, |
| 1821 | .section => |si| switch (elf.shdrSlice()) { | 1823 | .section => |si| switch (elf.symPtr(si)) { |
| 1822 | inline else => |shdr, class| { | 1824 | inline else => |sym, class| { |
| 1823 | const sym = @field(elf.symPtr(si), @tagName(class)); | 1825 | const sh = &@field(elf.shdrSlice(), @tagName(class))[elf.targetLoad(&sym.shndx)]; |
| 1824 | const shndx = std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian); | 1826 | elf.targetStore(&sh.size, @intCast(size)); |
| 1825 | const sh = &shdr[shndx]; | 1827 | switch (elf.targetLoad(&sh.type)) { |
| 1826 | switch (std.mem.toNative(@TypeOf(sh.type), sh.type, target_endian)) { | ||
| 1827 | else => unreachable, | 1828 | else => unreachable, |
| 1828 | std.elf.SHT_NULL => { | 1829 | std.elf.SHT_NULL => if (size > 0) elf.targetStore(&sh.type, std.elf.SHT_PROGBITS), |
| 1829 | if (size > 0) sh.type = std.mem.nativeTo( | 1830 | std.elf.SHT_PROGBITS => if (size == 0) elf.targetStore(&sh.type, std.elf.SHT_NULL), |
| 1830 | @TypeOf(sh.type), | 1831 | std.elf.SHT_SYMTAB => elf.targetStore( |
| 1831 | std.elf.SHT_PROGBITS, | 1832 | &sh.info, |
| 1832 | target_endian, | 1833 | @intCast(@divExact(size, elf.targetLoad(&sh.entsize))), |
| 1833 | ); | ||
| 1834 | }, | ||
| 1835 | std.elf.SHT_PROGBITS => { | ||
| 1836 | if (size == 0) sh.type = std.mem.nativeTo( | ||
| 1837 | @TypeOf(sh.type), | ||
| 1838 | std.elf.SHT_NULL, | ||
| 1839 | target_endian, | ||
| 1840 | ); | ||
| 1841 | }, | ||
| 1842 | std.elf.SHT_SYMTAB => sh.info = std.mem.nativeTo( | ||
| 1843 | @TypeOf(sh.info), | ||
| 1844 | @intCast(@divExact( | ||
| 1845 | size, | ||
| 1846 | std.mem.toNative(@TypeOf(sh.entsize), sh.entsize, target_endian), | ||
| 1847 | )), | ||
| 1848 | target_endian, | ||
| 1849 | ), | 1834 | ), |
| 1850 | std.elf.SHT_STRTAB => {}, | 1835 | std.elf.SHT_STRTAB => {}, |
| 1851 | } | 1836 | } |
| 1852 | sh.size = std.mem.nativeTo(@TypeOf(sh.size), @intCast(size), target_endian); | ||
| 1853 | }, | 1837 | }, |
| 1854 | }, | 1838 | }, |
| 1855 | .nav, .uav, .lazy_code, .lazy_const_data => {}, | 1839 | .nav, .uav, .lazy_code, .lazy_const_data => {}, |