| ... | @@ -23,6 +23,11 @@ const implib = @import("../libs/mingw/implib.zig"); | ... | @@ -23,6 +23,11 @@ const implib = @import("../libs/mingw/implib.zig"); |
| 23 | base: link.File, | 23 | base: link.File, |
| 24 | mf: MappedFile, | 24 | mf: MappedFile, |
| 25 | nodes: std.MultiArrayList(Node), | 25 | nodes: std.MultiArrayList(Node), |
| | 26 | members: std.ArrayList(Member), |
| | 27 | pending_members: std.AutoArrayHashMapUnmanaged(Member.Index, void), |
| | 28 | lib_string_table: std.ArrayList(String), |
| | 29 | lib_string_len: u64, |
| | 30 | long_names_table: LongNamesTable, |
| 26 | import_table: ImportTable, | 31 | import_table: ImportTable, |
| 27 | export_table: ExportTable, | 32 | export_table: ExportTable, |
| 28 | strings: std.HashMapUnmanaged( | 33 | strings: std.HashMapUnmanaged( |
| ... | @@ -137,18 +142,27 @@ pub const msdos_stub: [120]u8 = .{ | ... | @@ -137,18 +142,27 @@ pub const msdos_stub: [120]u8 = .{ |
| 137 | pub const Node = union(enum) { | 142 | pub const Node = union(enum) { |
| 138 | file, | 143 | file, |
| 139 | header, | 144 | header, |
| | 145 | /// Images and archives only. |
| 140 | signature, | 146 | signature, |
| | 147 | /// Archives only. |
| | 148 | archive_member_header: Member.Index, |
| | 149 | archive_member: Member.Index, |
| | 150 | |
| 141 | coff_header, | 151 | coff_header, |
| | 152 | /// Image only |
| 142 | optional_header, | 153 | optional_header, |
| | 154 | /// Image only |
| 143 | data_directories, | 155 | data_directories, |
| 144 | section_table, | 156 | section_table, |
| 145 | image_section: Symbol.Index, | 157 | image_section: Symbol.Index, |
| 146 | | 158 | |
| | 159 | /// Only images contain imports |
| 147 | import_directory_table, | 160 | import_directory_table, |
| 148 | import_lookup_table: ImportTable.Index, | 161 | import_lookup_table: ImportTable.Index, |
| 149 | import_address_table: ImportTable.Index, | 162 | import_address_table: ImportTable.Index, |
| 150 | import_hint_name_table: ImportTable.Index, | 163 | import_hint_name_table: ImportTable.Index, |
| 151 | | 164 | |
| | 165 | /// Only images contain exports |
| 152 | export_directory_table, | 166 | export_directory_table, |
| 153 | export_address_table, | 167 | export_address_table, |
| 154 | export_name_pointer_table, | 168 | export_name_pointer_table, |
| ... | @@ -163,6 +177,9 @@ pub const Node = union(enum) { | ... | @@ -163,6 +177,9 @@ pub const Node = union(enum) { |
| 163 | lazy_code: LazyMapRef.Index(.code), | 177 | lazy_code: LazyMapRef.Index(.code), |
| 164 | lazy_const_data: LazyMapRef.Index(.const_data), | 178 | lazy_const_data: LazyMapRef.Index(.const_data), |
| 165 | | 179 | |
| | 180 | /// Takes the place of a known node index when that node is not present in the output |
| | 181 | placeholder, |
| | 182 | |
| 166 | pub const PseudoSectionMapIndex = enum(u32) { | 183 | pub const PseudoSectionMapIndex = enum(u32) { |
| 167 | _, | 184 | _, |
| 168 | | 185 | |
| ... | @@ -262,6 +279,14 @@ pub const Node = union(enum) { | ... | @@ -262,6 +279,14 @@ pub const Node = union(enum) { |
| 262 | file, | 279 | file, |
| 263 | header, | 280 | header, |
| 264 | signature, | 281 | signature, |
| | 282 | first_linker_member_header, |
| | 283 | first_linker_member, |
| | 284 | second_linker_member_header, |
| | 285 | second_linker_member, |
| | 286 | longnames_member_header, |
| | 287 | longnames_member, |
| | 288 | zcu_member_header, |
| | 289 | zcu_member, |
| 265 | coff_header, | 290 | coff_header, |
| 266 | optional_header, | 291 | optional_header, |
| 267 | data_directories, | 292 | data_directories, |
| ... | @@ -279,8 +304,141 @@ pub const Node = union(enum) { | ... | @@ -279,8 +304,141 @@ pub const Node = union(enum) { |
| 279 | } | 304 | } |
| 280 | }; | 305 | }; |
| 281 | | 306 | |
| | 307 | pub const Member = struct { |
| | 308 | kind: Kind, |
| | 309 | header_ni: MappedFile.Node.Index, |
| | 310 | content_ni: MappedFile.Node.Index, |
| | 311 | // Maps symbols contained in this member to their index in the first linker member's symbol table |
| | 312 | // TODO: This could contain information about the name string if we need |
| | 313 | symbol_offsets: std.AutoArrayHashMapUnmanaged(Symbol.Index, u33), |
| | 314 | |
| | 315 | pub const Kind = enum { |
| | 316 | first_linker, |
| | 317 | second_linker, |
| | 318 | longnames, |
| | 319 | coff, |
| | 320 | import, |
| | 321 | }; |
| | 322 | |
| | 323 | pub const Index = enum(u16) { |
| | 324 | first, |
| | 325 | second, |
| | 326 | longnames, |
| | 327 | _, |
| | 328 | |
| | 329 | const known_count = @typeInfo(Index).@"enum".fields.len; |
| | 330 | |
| | 331 | pub fn get(member_index: Member.Index, coff: *Coff) *Member { |
| | 332 | return &coff.members.items[@intFromEnum(member_index)]; |
| | 333 | } |
| | 334 | }; |
| | 335 | |
| | 336 | pub fn headerPtr(member: *Member, coff: *Coff) *std.coff.ArchiveMemberHeader { |
| | 337 | return @ptrCast(@alignCast(member.header_ni.slice(&coff.mf))); |
| | 338 | } |
| | 339 | |
| | 340 | pub fn initHeader(member: *Member, coff: *Coff, name: []const u8, timestamp: u32) !void { |
| | 341 | const header = member.headerPtr(coff); |
| | 342 | try storeHeaderName(coff, &header.name, name); |
| | 343 | storeHeaderDecimalStr(&header.date, timestamp); |
| | 344 | |
| | 345 | // Matching the Microsoft behaviour of emitting blanks for these fields |
| | 346 | header.user_id = @splat(' '); |
| | 347 | header.group_id = @splat(' '); |
| | 348 | |
| | 349 | // file_mode is actually octal, but we only ever write 0 to it |
| | 350 | storeHeaderDecimalStr(&header.file_mode, 0); |
| | 351 | if (!member.content_ni.hasResized(&coff.mf)) |
| | 352 | storeHeaderDecimalStr( |
| | 353 | &header.size, |
| | 354 | member.content_ni.location(&coff.mf).resolve(&coff.mf)[1], |
| | 355 | ); |
| | 356 | |
| | 357 | @memcpy(&header.end_of_header, "`\n"); |
| | 358 | } |
| | 359 | |
| | 360 | /// Sets `name` as the name field of this member's header, either directly (if it's short enough), |
| | 361 | /// or by creating an entry in the longnames member and storing a reference to that entry. |
| | 362 | pub fn storeHeaderName(coff: *Coff, field: *[16]u8, name: []const u8) !void { |
| | 363 | if (name.len < field.len) { |
| | 364 | @memcpy(field[0..name.len], name); |
| | 365 | field[name.len] = '/'; |
| | 366 | const padding = field.len - name.len - 1; |
| | 367 | if (padding > 0) @memset(field[field.len - padding ..], ' '); |
| | 368 | } else { |
| | 369 | const gpa = coff.base.comp.gpa; |
| | 370 | const entries_ctx = LongNamesTable.Adapter{ .coff = coff }; |
| | 371 | const gop = try coff.long_names_table.entries.getOrPutAdapted( |
| | 372 | gpa, |
| | 373 | name, |
| | 374 | entries_ctx, |
| | 375 | ); |
| | 376 | |
| | 377 | if (!gop.found_existing) { |
| | 378 | errdefer _ = coff.export_table.entries.pop(); |
| | 379 | |
| | 380 | _, const old_size = Node.known.longnames_member.location(&coff.mf).resolve(&coff.mf); |
| | 381 | const new_size = old_size + name.len + 1; |
| | 382 | assert(new_size < comptime try std.math.powi(u64, 10, field.len - 1)); |
| | 383 | |
| | 384 | try Node.known.longnames_member.resize(&coff.mf, gpa, new_size); |
| | 385 | const name_table_slice = Node.known.longnames_member.slice(&coff.mf); |
| | 386 | const name_slice = name_table_slice[old_size..][0 .. name.len + 1]; |
| | 387 | @memcpy(name_slice[0..name.len], name); |
| | 388 | name_slice[name.len] = 0; |
| | 389 | |
| | 390 | gop.value_ptr.* = .{ |
| | 391 | .index = old_size, |
| | 392 | .len = name.len, |
| | 393 | }; |
| | 394 | } |
| | 395 | |
| | 396 | field[0] = '/'; |
| | 397 | storeHeaderDecimalStr(field[1..], gop.value_ptr.index); |
| | 398 | } |
| | 399 | } |
| | 400 | |
| | 401 | pub fn storeHeaderDecimalStr(field_ptr: anytype, value: u64) void { |
| | 402 | const array_info = @typeInfo(@typeInfo(@TypeOf(field_ptr)).pointer.child).array; |
| | 403 | assert(array_info.child == u8); |
| | 404 | assert(value < comptime try std.math.powi(u64, 10, array_info.len)); |
| | 405 | _ = std.fmt.printInt(field_ptr, value, 10, .lower, .{ |
| | 406 | .width = array_info.len, |
| | 407 | .alignment = .left, |
| | 408 | .fill = ' ', |
| | 409 | }); |
| | 410 | } |
| | 411 | }; |
| | 412 | |
| | 413 | pub const LongNamesTable = struct { |
| | 414 | ni: MappedFile.Node.Index = .none, |
| | 415 | entries: std.AutoArrayHashMapUnmanaged(void, Entry), |
| | 416 | |
| | 417 | pub const Entry = struct { |
| | 418 | index: u64, |
| | 419 | len: u64, |
| | 420 | }; |
| | 421 | |
| | 422 | const Adapter = struct { |
| | 423 | coff: *Coff, |
| | 424 | |
| | 425 | pub fn eql(adapter: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool { |
| | 426 | assert(adapter.coff.isArchive()); // TODO: move to helper that uses this |
| | 427 | const longnames_slice = Node.known.longnames_member.slice(&adapter.coff.mf); |
| | 428 | const rhs = adapter.coff.long_names_table.entries.values()[rhs_index]; |
| | 429 | return std.mem.eql(u8, longnames_slice[rhs.index..][0..rhs.len], lhs_key); |
| | 430 | } |
| | 431 | |
| | 432 | pub fn hash(_: Adapter, key: []const u8) u32 { |
| | 433 | assert(std.mem.indexOfScalar(u8, key, 0) == null); |
| | 434 | return std.array_hash_map.hashString(key); |
| | 435 | } |
| | 436 | }; |
| | 437 | }; |
| | 438 | |
| 282 | pub const ExportTable = struct { | 439 | pub const ExportTable = struct { |
| 283 | ni: MappedFile.Node.Index, | 440 | ni: MappedFile.Node.Index, |
| | 441 | export_directory_table_ni: MappedFile.Node.Index, |
| 284 | export_address_table_si: Symbol.Index, | 442 | export_address_table_si: Symbol.Index, |
| 285 | name_pointer_table_ni: MappedFile.Node.Index, | 443 | name_pointer_table_ni: MappedFile.Node.Index, |
| 286 | ordinal_table_ni: MappedFile.Node.Index, | 444 | ordinal_table_ni: MappedFile.Node.Index, |
| ... | @@ -535,6 +693,13 @@ pub const Reloc = extern struct { | ... | @@ -535,6 +693,13 @@ pub const Reloc = extern struct { |
| 535 | const loc_slice = loc_sym.ni.slice(&coff.mf)[@intCast(reloc.offset)..]; | 693 | const loc_slice = loc_sym.ni.slice(&coff.mf)[@intCast(reloc.offset)..]; |
| 536 | const target_rva = target_sym.rva +% @as(u64, @bitCast(reloc.addend)); | 694 | const target_rva = target_sym.rva +% @as(u64, @bitCast(reloc.addend)); |
| 537 | const target_endian = coff.targetEndian(); | 695 | const target_endian = coff.targetEndian(); |
| | 696 | |
| | 697 | // TODO: Is this right? |
| | 698 | const base = if (coff.isImage()) |
| | 699 | coff.optionalHeaderField(.image_base) |
| | 700 | else |
| | 701 | 0; // should be offset within section - take target_rva - section_rva (but section is 0!) |
| | 702 | |
| 538 | switch (coff.targetLoad(&coff.headerPtr().machine)) { | 703 | switch (coff.targetLoad(&coff.headerPtr().machine)) { |
| 539 | else => |machine| @panic(@tagName(machine)), | 704 | else => |machine| @panic(@tagName(machine)), |
| 540 | .AMD64 => switch (reloc.type.AMD64) { | 705 | .AMD64 => switch (reloc.type.AMD64) { |
| ... | @@ -543,13 +708,13 @@ pub const Reloc = extern struct { | ... | @@ -543,13 +708,13 @@ pub const Reloc = extern struct { |
| 543 | .ADDR64 => std.mem.writeInt( | 708 | .ADDR64 => std.mem.writeInt( |
| 544 | u64, | 709 | u64, |
| 545 | loc_slice[0..8], | 710 | loc_slice[0..8], |
| 546 | coff.optionalHeaderField(.image_base) + target_rva, | 711 | base + target_rva, |
| 547 | target_endian, | 712 | target_endian, |
| 548 | ), | 713 | ), |
| 549 | .ADDR32 => std.mem.writeInt( | 714 | .ADDR32 => std.mem.writeInt( |
| 550 | u32, | 715 | u32, |
| 551 | loc_slice[0..4], | 716 | loc_slice[0..4], |
| 552 | @intCast(coff.optionalHeaderField(.image_base) + target_rva), | 717 | @intCast(base + target_rva), |
| 553 | target_endian, | 718 | target_endian, |
| 554 | ), | 719 | ), |
| 555 | .ADDR32NB => std.mem.writeInt( | 720 | .ADDR32NB => std.mem.writeInt( |
| ... | @@ -607,7 +772,7 @@ pub const Reloc = extern struct { | ... | @@ -607,7 +772,7 @@ pub const Reloc = extern struct { |
| 607 | .DIR16 => std.mem.writeInt( | 772 | .DIR16 => std.mem.writeInt( |
| 608 | u16, | 773 | u16, |
| 609 | loc_slice[0..2], | 774 | loc_slice[0..2], |
| 610 | @intCast(coff.optionalHeaderField(.image_base) + target_rva), | 775 | @intCast(base + target_rva), |
| 611 | target_endian, | 776 | target_endian, |
| 612 | ), | 777 | ), |
| 613 | .REL16 => std.mem.writeInt( | 778 | .REL16 => std.mem.writeInt( |
| ... | @@ -619,7 +784,7 @@ pub const Reloc = extern struct { | ... | @@ -619,7 +784,7 @@ pub const Reloc = extern struct { |
| 619 | .DIR32 => std.mem.writeInt( | 784 | .DIR32 => std.mem.writeInt( |
| 620 | u32, | 785 | u32, |
| 621 | loc_slice[0..4], | 786 | loc_slice[0..4], |
| 622 | @intCast(coff.optionalHeaderField(.image_base) + target_rva), | 787 | @intCast(base + target_rva), |
| 623 | target_endian, | 788 | target_endian, |
| 624 | ), | 789 | ), |
| 625 | .DIR32NB => std.mem.writeInt( | 790 | .DIR32NB => std.mem.writeInt( |
| ... | @@ -691,14 +856,6 @@ fn create( | ... | @@ -691,14 +856,6 @@ fn create( |
| 691 | assert(target.ofmt == .coff); | 856 | assert(target.ofmt == .coff); |
| 692 | if (target.cpu.arch.endian() != comptime targetEndian(undefined)) | 857 | if (target.cpu.arch.endian() != comptime targetEndian(undefined)) |
| 693 | return error.UnsupportedCOFFArchitecture; | 858 | return error.UnsupportedCOFFArchitecture; |
| 694 | const is_image = switch (comp.config.output_mode) { | | |
| 695 | .Exe => true, | | |
| 696 | .Lib => switch (comp.config.link_mode) { | | |
| 697 | .static => false, | | |
| 698 | .dynamic => true, | | |
| 699 | }, | | |
| 700 | .Obj => false, | | |
| 701 | }; | | |
| 702 | const machine = target.toCoffMachine(); | 859 | const machine = target.toCoffMachine(); |
| 703 | const timestamp: u32 = 0; | 860 | const timestamp: u32 = 0; |
| 704 | const major_subsystem_version = options.major_subsystem_version orelse 6; | 861 | const major_subsystem_version = options.major_subsystem_version orelse 6; |
| ... | @@ -743,12 +900,20 @@ fn create( | ... | @@ -743,12 +900,20 @@ fn create( |
| 743 | }, | 900 | }, |
| 744 | .mf = try .init(file, comp.gpa, io), | 901 | .mf = try .init(file, comp.gpa, io), |
| 745 | .nodes = .empty, | 902 | .nodes = .empty, |
| | 903 | .members = .empty, |
| | 904 | .pending_members = .empty, |
| | 905 | .lib_string_table = .empty, |
| | 906 | .lib_string_len = 0, |
| | 907 | .long_names_table = .{ |
| | 908 | .entries = .empty, |
| | 909 | }, |
| 746 | .import_table = .{ | 910 | .import_table = .{ |
| 747 | .ni = .none, | 911 | .ni = .none, |
| 748 | .entries = .empty, | 912 | .entries = .empty, |
| 749 | }, | 913 | }, |
| 750 | .export_table = .{ | 914 | .export_table = .{ |
| 751 | .ni = .none, | 915 | .ni = .none, |
| | 916 | .export_directory_table_ni = .none, |
| 752 | .export_address_table_si = .null, | 917 | .export_address_table_si = .null, |
| 753 | .name_pointer_table_ni = .none, | 918 | .name_pointer_table_ni = .none, |
| 754 | .ordinal_table_ni = .none, | 919 | .ordinal_table_ni = .none, |
| ... | @@ -785,7 +950,6 @@ fn create( | ... | @@ -785,7 +950,6 @@ fn create( |
| 785 | } | 950 | } |
| 786 | | 951 | |
| 787 | try coff.initHeaders( | 952 | try coff.initHeaders( |
| 788 | is_image, | | |
| 789 | machine, | 953 | machine, |
| 790 | timestamp, | 954 | timestamp, |
| 791 | major_subsystem_version, | 955 | major_subsystem_version, |
| ... | @@ -801,6 +965,7 @@ pub fn deinit(coff: *Coff) void { | ... | @@ -801,6 +965,7 @@ pub fn deinit(coff: *Coff) void { |
| 801 | const gpa = coff.base.comp.gpa; | 965 | const gpa = coff.base.comp.gpa; |
| 802 | coff.mf.deinit(gpa); | 966 | coff.mf.deinit(gpa); |
| 803 | coff.nodes.deinit(gpa); | 967 | coff.nodes.deinit(gpa); |
| | 968 | coff.long_names_table.entries.deinit(gpa); |
| 804 | coff.import_table.entries.deinit(gpa); | 969 | coff.import_table.entries.deinit(gpa); |
| 805 | coff.export_table.entries.deinit(gpa); | 970 | coff.export_table.entries.deinit(gpa); |
| 806 | coff.strings.deinit(gpa); | 971 | coff.strings.deinit(gpa); |
| ... | @@ -818,9 +983,32 @@ pub fn deinit(coff: *Coff) void { | ... | @@ -818,9 +983,32 @@ pub fn deinit(coff: *Coff) void { |
| 818 | coff.* = undefined; | 983 | coff.* = undefined; |
| 819 | } | 984 | } |
| 820 | | 985 | |
| | 986 | fn isImage(coff: *const Coff) bool { |
| | 987 | const comp = coff.base.comp; |
| | 988 | return switch (comp.config.output_mode) { |
| | 989 | .Exe => true, |
| | 990 | .Lib => switch (comp.config.link_mode) { |
| | 991 | .static => false, |
| | 992 | .dynamic => true, |
| | 993 | }, |
| | 994 | .Obj => false, |
| | 995 | }; |
| | 996 | } |
| | 997 | |
| | 998 | fn isArchive(coff: *const Coff) bool { |
| | 999 | const comp = coff.base.comp; |
| | 1000 | return switch (comp.config.output_mode) { |
| | 1001 | .Exe => false, |
| | 1002 | .Lib => switch (comp.config.link_mode) { |
| | 1003 | .static => true, |
| | 1004 | .dynamic => false, |
| | 1005 | }, |
| | 1006 | .Obj => false, |
| | 1007 | }; |
| | 1008 | } |
| | 1009 | |
| 821 | fn initHeaders( | 1010 | fn initHeaders( |
| 822 | coff: *Coff, | 1011 | coff: *Coff, |
| 823 | is_image: bool, | | |
| 824 | machine: std.coff.IMAGE.FILE.MACHINE, | 1012 | machine: std.coff.IMAGE.FILE.MACHINE, |
| 825 | timestamp: u32, | 1013 | timestamp: u32, |
| 826 | major_subsystem_version: u16, | 1014 | major_subsystem_version: u16, |
| ... | @@ -833,6 +1021,8 @@ fn initHeaders( | ... | @@ -833,6 +1021,8 @@ fn initHeaders( |
| 833 | const gpa = comp.gpa; | 1021 | const gpa = comp.gpa; |
| 834 | const target_endian = coff.targetEndian(); | 1022 | const target_endian = coff.targetEndian(); |
| 835 | const file_align: std.mem.Alignment = comptime .fromByteUnits(default_file_alignment); | 1023 | const file_align: std.mem.Alignment = comptime .fromByteUnits(default_file_alignment); |
| | 1024 | const is_image = coff.isImage(); |
| | 1025 | const is_archive = coff.isArchive(); |
| 836 | | 1026 | |
| 837 | const optional_header_size: u16 = if (is_image) switch (magic) { | 1027 | const optional_header_size: u16 = if (is_image) switch (magic) { |
| 838 | _ => unreachable, | 1028 | _ => unreachable, |
| ... | @@ -843,33 +1033,106 @@ fn initHeaders( | ... | @@ -843,33 +1033,106 @@ fn initHeaders( |
| 843 | else | 1033 | else |
| 844 | 0; | 1034 | 0; |
| 845 | | 1035 | |
| 846 | const expected_nodes_len = Node.known_count + 12 + | 1036 | var expected_nodes_len: usize = Node.known_count; |
| 847 | @as(usize, @intFromBool(comp.config.any_non_single_threaded)) * 2; | 1037 | if (comp.zcu != null) { |
| | 1038 | expected_nodes_len += 3; |
| | 1039 | if (is_image) expected_nodes_len += 9; |
| | 1040 | expected_nodes_len += @as(usize, @intFromBool(comp.config.any_non_single_threaded)) * 2; |
| | 1041 | } |
| | 1042 | defer assert(coff.nodes.len == expected_nodes_len); |
| | 1043 | |
| 848 | try coff.nodes.ensureTotalCapacity(gpa, expected_nodes_len); | 1044 | try coff.nodes.ensureTotalCapacity(gpa, expected_nodes_len); |
| 849 | coff.nodes.appendAssumeCapacity(.file); | 1045 | coff.nodes.appendAssumeCapacity(.file); |
| 850 | | 1046 | |
| 851 | const header_ni = Node.known.header; | 1047 | const header_ni = Node.known.header; |
| 852 | assert(header_ni == try coff.mf.addOnlyChildNode(gpa, .root, .{ | 1048 | assert(header_ni == try coff.mf.addOnlyChildNode(gpa, Node.known.file, .{ |
| 853 | .alignment = coff.mf.flags.block_size, | 1049 | .alignment = coff.mf.flags.block_size, |
| 854 | .fixed = true, | 1050 | .fixed = true, |
| 855 | })); | 1051 | })); |
| 856 | coff.nodes.appendAssumeCapacity(.header); | 1052 | coff.nodes.appendAssumeCapacity(.header); |
| 857 | | 1053 | |
| | 1054 | const pe_signature = "PE\x00\x00"; |
| | 1055 | const archive_signature = "!<arch>\n"; |
| | 1056 | |
| 858 | const signature_ni = Node.known.signature; | 1057 | const signature_ni = Node.known.signature; |
| 859 | assert(signature_ni == try coff.mf.addOnlyChildNode(gpa, header_ni, .{ | 1058 | assert(signature_ni == try coff.mf.addLastChildNode(gpa, if (is_image) header_ni else Node.known.file, .{ |
| 860 | .size = (if (is_image) msdos_stub.len else 0) + "PE\x00\x00".len, | 1059 | .size = if (is_image) |
| | 1060 | msdos_stub.len + pe_signature.len |
| | 1061 | else if (is_archive) |
| | 1062 | archive_signature.len |
| | 1063 | else |
| | 1064 | 0, |
| 861 | .alignment = .@"4", | 1065 | .alignment = .@"4", |
| 862 | .fixed = true, | 1066 | .fixed = true, |
| 863 | })); | 1067 | })); |
| 864 | coff.nodes.appendAssumeCapacity(.signature); | 1068 | coff.nodes.appendAssumeCapacity(.signature); |
| 865 | { | 1069 | |
| 866 | const signature_slice = signature_ni.slice(&coff.mf); | 1070 | const signature_slice = signature_ni.slice(&coff.mf); |
| 867 | if (is_image) @memcpy(signature_slice[0..msdos_stub.len], &msdos_stub); | 1071 | if (is_image) { |
| 868 | @memcpy(signature_slice[signature_slice.len - 4 ..], "PE\x00\x00"); | 1072 | @memcpy(signature_slice[0..msdos_stub.len], &msdos_stub); |
| | 1073 | @memcpy(signature_slice[signature_slice.len - pe_signature.len ..], pe_signature); |
| | 1074 | } else if (is_archive) { |
| | 1075 | @memcpy(signature_slice, archive_signature); |
| 869 | } | 1076 | } |
| 870 | | 1077 | |
| | 1078 | const opt_zcu_coff_parent_ni = if (is_archive) parent: { |
| | 1079 | const initial_member_count = Member.Index.known_count + @intFromBool(comp.zcu != null); |
| | 1080 | try coff.members.ensureTotalCapacity(gpa, initial_member_count); |
| | 1081 | |
| | 1082 | assert(Member.Index.first == try coff.addMemberAssumeCapacity(.first_linker, @sizeOf(u32))); |
| | 1083 | coff.targetStore(coff.firstLinkerMemberNumSymbolsPtr(), 0); |
| | 1084 | |
| | 1085 | assert(Member.Index.second == try coff.addMemberAssumeCapacity(.second_linker, 2 * @sizeOf(u32))); |
| | 1086 | coff.targetStore(coff.secondLinkerMemberNumMembersPtr(), 0); |
| | 1087 | coff.targetStore(coff.secondLinkerMemberNumSymbolsPtr(), 0); |
| | 1088 | |
| | 1089 | assert(Member.Index.longnames == try coff.addMemberAssumeCapacity(.longnames, 0)); |
| | 1090 | |
| | 1091 | const first_linker_member = Member.Index.first.get(coff); |
| | 1092 | const second_linker_member = Member.Index.second.get(coff); |
| | 1093 | const longnames_member = Member.Index.longnames.get(coff); |
| | 1094 | |
| | 1095 | try first_linker_member.initHeader(coff, "", timestamp); |
| | 1096 | try second_linker_member.initHeader(coff, "", timestamp); |
| | 1097 | try longnames_member.initHeader(coff, "/", timestamp); |
| | 1098 | |
| | 1099 | if (comp.zcu) |zcu| { |
| | 1100 | const zcu_mi = try coff.addMemberAssumeCapacity(.coff, @sizeOf(std.coff.Header)); |
| | 1101 | const zcu_member = zcu_mi.get(coff); |
| | 1102 | try zcu_member.initHeader(coff, zcu.main_mod.fully_qualified_name, timestamp); |
| | 1103 | |
| | 1104 | break :parent zcu_member.content_ni; |
| | 1105 | } |
| | 1106 | |
| | 1107 | assert(Node.known.zcu_member_header == try coff.mf.addLastChildNode(gpa, Node.known.file, .{})); |
| | 1108 | assert(Node.known.zcu_member == try coff.mf.addLastChildNode(gpa, Node.known.file, .{})); |
| | 1109 | coff.nodes.appendAssumeCapacity(.placeholder); |
| | 1110 | coff.nodes.appendAssumeCapacity(.placeholder); |
| | 1111 | |
| | 1112 | break :parent null; |
| | 1113 | } else parent: { |
| | 1114 | // TODO: Not ideal to have this many placeholder nodes - use two distinct `Node.known` types? |
| | 1115 | while (true) { |
| | 1116 | const placeholder_ni = try coff.mf.addLastChildNode(gpa, Node.known.file, .{}); |
| | 1117 | coff.nodes.appendAssumeCapacity(.placeholder); |
| | 1118 | if (placeholder_ni == Node.known.zcu_member) break; |
| | 1119 | } |
| | 1120 | |
| | 1121 | break :parent if (comp.zcu != null) Node.known.header else null; |
| | 1122 | }; |
| | 1123 | |
| | 1124 | const zcu_coff_parent_ni = opt_zcu_coff_parent_ni orelse { |
| | 1125 | // If we're not generating any code, no more known nodes are used |
| | 1126 | while (coff.nodes.len < Node.known_count) { |
| | 1127 | _ = try coff.mf.addLastChildNode(gpa, Node.known.file, .{}); |
| | 1128 | coff.nodes.appendAssumeCapacity(.placeholder); |
| | 1129 | } |
| | 1130 | |
| | 1131 | return; |
| | 1132 | }; |
| | 1133 | |
| 871 | const coff_header_ni = Node.known.coff_header; | 1134 | const coff_header_ni = Node.known.coff_header; |
| 872 | assert(coff_header_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ | 1135 | assert(coff_header_ni == try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{ |
| 873 | .size = @sizeOf(std.coff.Header), | 1136 | .size = @sizeOf(std.coff.Header), |
| 874 | .alignment = .@"4", | 1137 | .alignment = .@"4", |
| 875 | .fixed = true, | 1138 | .fixed = true, |
| ... | @@ -897,7 +1160,7 @@ fn initHeaders( | ... | @@ -897,7 +1160,7 @@ fn initHeaders( |
| 897 | } | 1160 | } |
| 898 | | 1161 | |
| 899 | const optional_header_ni = Node.known.optional_header; | 1162 | const optional_header_ni = Node.known.optional_header; |
| 900 | assert(optional_header_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ | 1163 | assert(optional_header_ni == try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{ |
| 901 | .size = optional_header_size, | 1164 | .size = optional_header_size, |
| 902 | .alignment = .@"4", | 1165 | .alignment = .@"4", |
| 903 | .fixed = true, | 1166 | .fixed = true, |
| ... | @@ -1009,13 +1272,13 @@ fn initHeaders( | ... | @@ -1009,13 +1272,13 @@ fn initHeaders( |
| 1009 | } | 1272 | } |
| 1010 | | 1273 | |
| 1011 | const data_directories_ni = Node.known.data_directories; | 1274 | const data_directories_ni = Node.known.data_directories; |
| 1012 | assert(data_directories_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ | 1275 | assert(data_directories_ni == try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{ |
| 1013 | .size = data_directories_size, | 1276 | .size = data_directories_size, |
| 1014 | .alignment = .@"4", | 1277 | .alignment = .@"4", |
| 1015 | .fixed = true, | 1278 | .fixed = true, |
| 1016 | })); | 1279 | })); |
| 1017 | coff.nodes.appendAssumeCapacity(.data_directories); | 1280 | coff.nodes.appendAssumeCapacity(.data_directories); |
| 1018 | { | 1281 | if (is_image) { |
| 1019 | const data_directories = coff.dataDirectorySlice(); | 1282 | const data_directories = coff.dataDirectorySlice(); |
| 1020 | @memset(data_directories, .{ .virtual_address = 0, .size = 0 }); | 1283 | @memset(data_directories, .{ .virtual_address = 0, .size = 0 }); |
| 1021 | if (target_endian != native_endian) std.mem.byteSwapAllFields( | 1284 | if (target_endian != native_endian) std.mem.byteSwapAllFields( |
| ... | @@ -1025,7 +1288,7 @@ fn initHeaders( | ... | @@ -1025,7 +1288,7 @@ fn initHeaders( |
| 1025 | } | 1288 | } |
| 1026 | | 1289 | |
| 1027 | const section_table_ni = Node.known.section_table; | 1290 | const section_table_ni = Node.known.section_table; |
| 1028 | assert(section_table_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ | 1291 | assert(section_table_ni == try coff.mf.addLastChildNode(gpa, zcu_coff_parent_ni, .{ |
| 1029 | .alignment = .@"4", | 1292 | .alignment = .@"4", |
| 1030 | .fixed = true, | 1293 | .fixed = true, |
| 1031 | })); | 1294 | })); |
| ... | @@ -1057,43 +1320,45 @@ fn initHeaders( | ... | @@ -1057,43 +1320,45 @@ fn initHeaders( |
| 1057 | .MEM_READ = true, | 1320 | .MEM_READ = true, |
| 1058 | }) == .text); | 1321 | }) == .text); |
| 1059 | | 1322 | |
| 1060 | coff.import_table.ni = try coff.mf.addLastChildNode( | | |
| 1061 | gpa, | | |
| 1062 | (try coff.objectSectionMapIndex( | | |
| 1063 | .@".idata", | | |
| 1064 | coff.mf.flags.block_size, | | |
| 1065 | .{ .read = true }, | | |
| 1066 | )).symbol(coff).node(coff), | | |
| 1067 | .{ .alignment = .@"4", .moved = true }, | | |
| 1068 | ); | | |
| 1069 | coff.nodes.appendAssumeCapacity(.import_directory_table); | | |
| 1070 | | | |
| 1071 | if (is_image) { | 1323 | if (is_image) { |
| 1072 | const edata_section_ni = (try coff.pseudoSectionMapIndex( | 1324 | coff.import_table.ni = try coff.mf.addLastChildNode( |
| | 1325 | gpa, |
| | 1326 | (try coff.objectSectionMapIndex( |
| | 1327 | .@".idata", |
| | 1328 | coff.mf.flags.block_size, |
| | 1329 | .{ .read = true }, |
| | 1330 | )).symbol(coff).node(coff), |
| | 1331 | .{ .alignment = .@"4", .moved = true }, |
| | 1332 | ); |
| | 1333 | coff.nodes.appendAssumeCapacity(.import_directory_table); |
| | 1334 | |
| | 1335 | coff.export_table.ni = (try coff.pseudoSectionMapIndex( |
| 1073 | .@".edata", | 1336 | .@".edata", |
| 1074 | .of(std.coff.ExportDirectoryTable), | 1337 | .of(std.coff.ExportDirectoryTable), |
| 1075 | .{ .read = true }, | 1338 | .{ .read = true }, |
| 1076 | )).symbol(coff).node(coff); | 1339 | )).symbol(coff).node(coff); |
| 1077 | | 1340 | |
| 1078 | coff.export_table.ni = try coff.mf.addLastChildNode( | 1341 | coff.export_table.export_directory_table_ni = try coff.mf.addLastChildNode( |
| 1079 | gpa, | 1342 | gpa, |
| 1080 | edata_section_ni, | 1343 | coff.export_table.ni, |
| 1081 | .{ | 1344 | .{ |
| 1082 | .size = @sizeOf(std.coff.ExportDirectoryTable) + file_name.len + 1, | 1345 | .size = @sizeOf(std.coff.ExportDirectoryTable) + file_name.len + 1, |
| 1083 | .alignment = .of(std.coff.ExportDirectoryTable), | | |
| 1084 | .fixed = true, | | |
| 1085 | .moved = true, | 1346 | .moved = true, |
| | 1347 | .fixed = true, |
| 1086 | }, | 1348 | }, |
| 1087 | ); | 1349 | ); |
| | 1350 | coff.nodes.appendAssumeCapacity(.export_directory_table); |
| 1088 | | 1351 | |
| 1089 | const name_index = @sizeOf(std.coff.ExportDirectoryTable); | 1352 | const name_index = @sizeOf(std.coff.ExportDirectoryTable); |
| 1090 | @memcpy(coff.export_table.ni.slice(&coff.mf)[name_index..][0..file_name.len], file_name[0..file_name.len]); | 1353 | const table_slice = coff.export_table.export_directory_table_ni.slice(&coff.mf); |
| 1091 | @memset(coff.export_table.ni.slice(&coff.mf)[name_index + file_name.len ..], 0); | 1354 | @memcpy(table_slice[name_index..][0..file_name.len], file_name[0..file_name.len]); |
| | 1355 | @memset(table_slice[name_index + file_name.len ..], 0); |
| 1092 | | 1356 | |
| 1093 | const export_address_table_ni = try coff.mf.addLastChildNode(gpa, edata_section_ni, .{ | 1357 | const export_address_table_ni = try coff.mf.addLastChildNode(gpa, coff.export_table.ni, .{ |
| 1094 | .alignment = .of(u32), | 1358 | .alignment = .of(std.coff.ExportAddressTableEntry), |
| 1095 | .moved = true, | 1359 | .moved = true, |
| 1096 | }); | 1360 | }); |
| | 1361 | coff.nodes.appendAssumeCapacity(.export_address_table); |
| 1097 | | 1362 | |
| 1098 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | 1363 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); |
| 1099 | coff.export_table.export_address_table_si = coff.addSymbolAssumeCapacity(); | 1364 | coff.export_table.export_address_table_si = coff.addSymbolAssumeCapacity(); |
| ... | @@ -1103,25 +1368,24 @@ fn initHeaders( | ... | @@ -1103,25 +1368,24 @@ fn initHeaders( |
| 1103 | assert(export_address_table_sym.loc_relocs == .none); | 1368 | assert(export_address_table_sym.loc_relocs == .none); |
| 1104 | export_address_table_sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | 1369 | export_address_table_sym.loc_relocs = @enumFromInt(coff.relocs.items.len); |
| 1105 | export_address_table_sym.section_number = | 1370 | export_address_table_sym.section_number = |
| 1106 | coff.getNode(edata_section_ni).pseudo_section.symbol(coff).get(coff).section_number; | 1371 | coff.getNode(coff.export_table.ni).pseudo_section.symbol(coff).get(coff).section_number; |
| 1107 | | 1372 | |
| 1108 | coff.export_table.name_pointer_table_ni = try coff.mf.addLastChildNode(gpa, edata_section_ni, .{ | 1373 | coff.export_table.name_pointer_table_ni = try coff.mf.addLastChildNode(gpa, coff.export_table.ni, .{ |
| 1109 | .alignment = .of(u32), | 1374 | .alignment = .of(std.coff.ExportNamePointerTableEntry), |
| 1110 | .moved = true, | 1375 | .moved = true, |
| 1111 | }); | 1376 | }); |
| 1112 | coff.export_table.ordinal_table_ni = try coff.mf.addLastChildNode(gpa, edata_section_ni, .{ | 1377 | coff.nodes.appendAssumeCapacity(.export_name_pointer_table); |
| 1113 | .alignment = .of(u16), | 1378 | |
| | 1379 | coff.export_table.ordinal_table_ni = try coff.mf.addLastChildNode(gpa, coff.export_table.ni, .{ |
| | 1380 | .alignment = .of(std.coff.ExportOrdinalTableEntry), |
| 1114 | .moved = true, | 1381 | .moved = true, |
| 1115 | }); | 1382 | }); |
| 1116 | coff.export_table.name_table_ni = try coff.mf.addLastChildNode(gpa, edata_section_ni, .{ | 1383 | coff.nodes.appendAssumeCapacity(.export_ordinal_table); |
| | 1384 | |
| | 1385 | coff.export_table.name_table_ni = try coff.mf.addLastChildNode(gpa, coff.export_table.ni, .{ |
| 1117 | .alignment = .of(u8), | 1386 | .alignment = .of(u8), |
| 1118 | .moved = true, | 1387 | .moved = true, |
| 1119 | }); | 1388 | }); |
| 1120 | | | |
| 1121 | coff.nodes.appendAssumeCapacity(.export_directory_table); | | |
| 1122 | coff.nodes.appendAssumeCapacity(.export_address_table); | | |
| 1123 | coff.nodes.appendAssumeCapacity(.export_name_pointer_table); | | |
| 1124 | coff.nodes.appendAssumeCapacity(.export_ordinal_table); | | |
| 1125 | coff.nodes.appendAssumeCapacity(.export_name_table); | 1389 | coff.nodes.appendAssumeCapacity(.export_name_table); |
| 1126 | | 1390 | |
| 1127 | const export_directory_table = coff.exportDirectoryTable(); | 1391 | const export_directory_table = coff.exportDirectoryTable(); |
| ... | @@ -1145,11 +1409,9 @@ fn initHeaders( | ... | @@ -1145,11 +1409,9 @@ fn initHeaders( |
| 1145 | // While tls variables allocated at runtime are writable, the template itself is not | 1409 | // While tls variables allocated at runtime are writable, the template itself is not |
| 1146 | if (comp.config.any_non_single_threaded) _ = try coff.objectSectionMapIndex( | 1410 | if (comp.config.any_non_single_threaded) _ = try coff.objectSectionMapIndex( |
| 1147 | .@".tls$", | 1411 | .@".tls$", |
| 1148 | coff.mf.flags.block_size, | 1412 | if (is_image) coff.mf.flags.block_size else .@"1", |
| 1149 | .{ .read = true }, | 1413 | .{ .read = true }, |
| 1150 | ); | 1414 | ); |
| 1151 | | | |
| 1152 | assert(coff.nodes.len == expected_nodes_len); | | |
| 1153 | } | 1415 | } |
| 1154 | | 1416 | |
| 1155 | pub fn startProgress(coff: *Coff, prog_node: std.Progress.Node) void { | 1417 | pub fn startProgress(coff: *Coff, prog_node: std.Progress.Node) void { |
| ... | @@ -1181,11 +1443,14 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 { | ... | @@ -1181,11 +1443,14 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 { |
| 1181 | .file, | 1443 | .file, |
| 1182 | .header, | 1444 | .header, |
| 1183 | .signature, | 1445 | .signature, |
| | 1446 | .archive_member_header, |
| | 1447 | .archive_member, |
| 1184 | .coff_header, | 1448 | .coff_header, |
| 1185 | .optional_header, | 1449 | .optional_header, |
| 1186 | .data_directories, | 1450 | .data_directories, |
| 1187 | .section_table, | 1451 | .section_table, |
| 1188 | .export_name_table, | 1452 | .export_name_table, |
| | 1453 | .placeholder, |
| 1189 | => unreachable, | 1454 | => unreachable, |
| 1190 | .image_section => |si| si, | 1455 | .image_section => |si| si, |
| 1191 | .import_directory_table => break :parent_rva coff.targetLoad( | 1456 | .import_directory_table => break :parent_rva coff.targetLoad( |
| ... | @@ -1272,9 +1537,55 @@ fn targetStore(coff: *const Coff, ptr: anytype, val: @typeInfo(@TypeOf(ptr)).poi | ... | @@ -1272,9 +1537,55 @@ fn targetStore(coff: *const Coff, ptr: anytype, val: @typeInfo(@TypeOf(ptr)).poi |
| 1272 | } | 1537 | } |
| 1273 | | 1538 | |
| 1274 | pub fn headerPtr(coff: *Coff) *std.coff.Header { | 1539 | pub fn headerPtr(coff: *Coff) *std.coff.Header { |
| | 1540 | assert(coff.base.comp.zcu != null); |
| 1275 | return @ptrCast(@alignCast(Node.known.coff_header.slice(&coff.mf))); | 1541 | return @ptrCast(@alignCast(Node.known.coff_header.slice(&coff.mf))); |
| 1276 | } | 1542 | } |
| 1277 | | 1543 | |
| | 1544 | pub fn firstLinkerMemberNumSymbolsPtr(coff: *Coff) *u32 { |
| | 1545 | assert(coff.isArchive()); |
| | 1546 | return @ptrCast(@alignCast(Node.known.first_linker_member.slice(&coff.mf))); |
| | 1547 | } |
| | 1548 | |
| | 1549 | pub fn firstLinkerMemberOffsetsSlice(coff: *Coff) []u32 { |
| | 1550 | const len = std.mem.toNative(u32, coff.firstLinkerMemberNumSymbolsPtr().*, .big); |
| | 1551 | return @ptrCast(@alignCast(Node.known.first_linker_member.slice(&coff.mf)[@sizeOf(u32)..][0 .. len * @sizeOf(u32)])); |
| | 1552 | } |
| | 1553 | |
| | 1554 | pub fn secondLinkerMemberNumMembersPtr(coff: *Coff) *u32 { |
| | 1555 | assert(coff.isArchive()); |
| | 1556 | return @ptrCast(@alignCast(Node.known.second_linker_member.slice(&coff.mf))); |
| | 1557 | } |
| | 1558 | |
| | 1559 | pub fn secondLinkerMemberOffsetsSlice(coff: *Coff) []u32 { |
| | 1560 | const num_members = coff.targetLoad(coff.secondLinkerMemberNumMembersPtr()); |
| | 1561 | return @ptrCast(@alignCast( |
| | 1562 | Node.known.second_linker_member.slice(&coff.mf)[@sizeOf(u32)..][0 .. num_members * @sizeOf(u32)], |
| | 1563 | )); |
| | 1564 | } |
| | 1565 | |
| | 1566 | pub fn secondLinkerMemberNumSymbolsPtr(coff: *Coff) *u32 { |
| | 1567 | const num_members = coff.targetLoad(coff.secondLinkerMemberNumMembersPtr()); |
| | 1568 | return @ptrCast(@alignCast( |
| | 1569 | Node.known.second_linker_member.slice(&coff.mf)[(1 + num_members) * @sizeOf(u32) ..], |
| | 1570 | )); |
| | 1571 | } |
| | 1572 | |
| | 1573 | pub fn secondLinkerMemberIndicesSlice(coff: *Coff) []u16 { |
| | 1574 | const num_members = coff.targetLoad(coff.secondLinkerMemberNumMembersPtr()); |
| | 1575 | const num_symbols = coff.targetLoad(coff.secondLinkerMemberNumSymbolsPtr()); |
| | 1576 | return @ptrCast(@alignCast( |
| | 1577 | Node.known.second_linker_member.slice(&coff.mf)[(2 + num_members) * @sizeOf(u32) ..][0 .. num_symbols * @sizeOf(u16)], |
| | 1578 | )); |
| | 1579 | } |
| | 1580 | |
| | 1581 | pub fn secondLinkerMemberStringsSlice(coff: *Coff) []u8 { |
| | 1582 | const num_members = coff.targetLoad(coff.secondLinkerMemberNumMembersPtr()); |
| | 1583 | const num_symbols = coff.targetLoad(coff.secondLinkerMemberNumSymbolsPtr()); |
| | 1584 | return @ptrCast(@alignCast( |
| | 1585 | Node.known.second_linker_member.slice(&coff.mf)[(2 + num_members) * @sizeOf(u32) + num_symbols * @sizeOf(u16) ..], |
| | 1586 | )); |
| | 1587 | } |
| | 1588 | |
| 1278 | pub fn optionalHeaderStandardPtr(coff: *Coff) *std.coff.OptionalHeader { | 1589 | pub fn optionalHeaderStandardPtr(coff: *Coff) *std.coff.OptionalHeader { |
| 1279 | return @ptrCast(@alignCast( | 1590 | return @ptrCast(@alignCast( |
| 1280 | Node.known.optional_header.slice(&coff.mf)[0..@sizeOf(std.coff.OptionalHeader)], | 1591 | Node.known.optional_header.slice(&coff.mf)[0..@sizeOf(std.coff.OptionalHeader)], |
| ... | @@ -1286,6 +1597,7 @@ pub const OptionalHeaderPtr = union(std.coff.OptionalHeader.Magic) { | ... | @@ -1286,6 +1597,7 @@ pub const OptionalHeaderPtr = union(std.coff.OptionalHeader.Magic) { |
| 1286 | @"PE32+": *std.coff.OptionalHeader.@"PE32+", | 1597 | @"PE32+": *std.coff.OptionalHeader.@"PE32+", |
| 1287 | }; | 1598 | }; |
| 1288 | pub fn optionalHeaderPtr(coff: *Coff) OptionalHeaderPtr { | 1599 | pub fn optionalHeaderPtr(coff: *Coff) OptionalHeaderPtr { |
| | 1600 | assert(coff.isImage()); |
| 1289 | const slice = Node.known.optional_header.slice(&coff.mf); | 1601 | const slice = Node.known.optional_header.slice(&coff.mf); |
| 1290 | return switch (coff.targetLoad(&coff.optionalHeaderStandardPtr().magic)) { | 1602 | return switch (coff.targetLoad(&coff.optionalHeaderStandardPtr().magic)) { |
| 1291 | _ => unreachable, | 1603 | _ => unreachable, |
| ... | @@ -1300,6 +1612,7 @@ pub fn optionalHeaderField( | ... | @@ -1300,6 +1612,7 @@ pub fn optionalHeaderField( |
| 1300 | coff: *Coff, | 1612 | coff: *Coff, |
| 1301 | comptime field: std.meta.FieldEnum(std.coff.OptionalHeader.@"PE32+"), | 1613 | comptime field: std.meta.FieldEnum(std.coff.OptionalHeader.@"PE32+"), |
| 1302 | ) @FieldType(std.coff.OptionalHeader.@"PE32+", @tagName(field)) { | 1614 | ) @FieldType(std.coff.OptionalHeader.@"PE32+", @tagName(field)) { |
| | 1615 | assert(coff.isImage()); |
| 1303 | return switch (coff.optionalHeaderPtr()) { | 1616 | return switch (coff.optionalHeaderPtr()) { |
| 1304 | inline else => |optional_header| coff.targetLoad(&@field(optional_header, @tagName(field))), | 1617 | inline else => |optional_header| coff.targetLoad(&@field(optional_header, @tagName(field))), |
| 1305 | }; | 1618 | }; |
| ... | @@ -1308,6 +1621,7 @@ pub fn optionalHeaderField( | ... | @@ -1308,6 +1621,7 @@ pub fn optionalHeaderField( |
| 1308 | pub fn dataDirectorySlice( | 1621 | pub fn dataDirectorySlice( |
| 1309 | coff: *Coff, | 1622 | coff: *Coff, |
| 1310 | ) *[std.coff.IMAGE.DIRECTORY_ENTRY.len]std.coff.ImageDataDirectory { | 1623 | ) *[std.coff.IMAGE.DIRECTORY_ENTRY.len]std.coff.ImageDataDirectory { |
| | 1624 | assert(coff.isImage()); |
| 1311 | return @ptrCast(@alignCast(Node.known.data_directories.slice(&coff.mf))); | 1625 | return @ptrCast(@alignCast(Node.known.data_directories.slice(&coff.mf))); |
| 1312 | } | 1626 | } |
| 1313 | pub fn dataDirectoryPtr( | 1627 | pub fn dataDirectoryPtr( |
| ... | @@ -1322,6 +1636,7 @@ pub fn sectionTableSlice(coff: *Coff) []std.coff.SectionHeader { | ... | @@ -1322,6 +1636,7 @@ pub fn sectionTableSlice(coff: *Coff) []std.coff.SectionHeader { |
| 1322 | } | 1636 | } |
| 1323 | | 1637 | |
| 1324 | pub fn importDirectoryTableSlice(coff: *Coff) []std.coff.ImportDirectoryEntry { | 1638 | pub fn importDirectoryTableSlice(coff: *Coff) []std.coff.ImportDirectoryEntry { |
| | 1639 | assert(coff.isImage()); |
| 1325 | return @ptrCast(@alignCast(coff.import_table.ni.slice(&coff.mf))); | 1640 | return @ptrCast(@alignCast(coff.import_table.ni.slice(&coff.mf))); |
| 1326 | } | 1641 | } |
| 1327 | pub fn importDirectoryEntryPtr( | 1642 | pub fn importDirectoryEntryPtr( |
| ... | @@ -1332,10 +1647,13 @@ pub fn importDirectoryEntryPtr( | ... | @@ -1332,10 +1647,13 @@ pub fn importDirectoryEntryPtr( |
| 1332 | } | 1647 | } |
| 1333 | | 1648 | |
| 1334 | pub fn exportDirectoryTable(coff: *Coff) *std.coff.ExportDirectoryTable { | 1649 | pub fn exportDirectoryTable(coff: *Coff) *std.coff.ExportDirectoryTable { |
| 1335 | return @ptrCast(@alignCast(coff.export_table.ni.slice(&coff.mf))); | 1650 | return @ptrCast(@alignCast(coff.export_table.export_directory_table_ni.slice(&coff.mf))); |
| 1336 | } | 1651 | } |
| 1337 | | 1652 | |
| 1338 | pub fn exportNamePointerTableSlice(coff: *Coff) []std.coff.ExportNamePointerTableEntry { | 1653 | pub fn exportNamePointerTableSlice(coff: *Coff) []std.coff.ExportNamePointerTableEntry { |
| | 1654 | const debug = coff.export_table.name_pointer_table_ni.slice(&coff.mf); |
| | 1655 | _ = debug; |
| | 1656 | |
| 1339 | return @ptrCast(@alignCast(coff.export_table.name_pointer_table_ni.slice(&coff.mf))); | 1657 | return @ptrCast(@alignCast(coff.export_table.name_pointer_table_ni.slice(&coff.mf))); |
| 1340 | } | 1658 | } |
| 1341 | | 1659 | |
| ... | @@ -1388,6 +1706,14 @@ fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String { | ... | @@ -1388,6 +1706,14 @@ fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String { |
| 1388 | } | 1706 | } |
| 1389 | | 1707 | |
| 1390 | pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbol.Index { | 1708 | pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbol.Index { |
| | 1709 | return (try getOrPutGlobalSymbol(coff, name, lib_name)).value_ptr.*; |
| | 1710 | } |
| | 1711 | |
| | 1712 | fn getOrPutGlobalSymbol( |
| | 1713 | coff: *Coff, |
| | 1714 | name: []const u8, |
| | 1715 | lib_name: ?[]const u8, |
| | 1716 | ) !std.AutoArrayHashMapUnmanaged(GlobalName, Symbol.Index).GetOrPutResult { |
| 1391 | const gpa = coff.base.comp.gpa; | 1717 | const gpa = coff.base.comp.gpa; |
| 1392 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | 1718 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); |
| 1393 | const sym_gop = try coff.globals.getOrPut(gpa, .{ | 1719 | const sym_gop = try coff.globals.getOrPut(gpa, .{ |
| ... | @@ -1398,7 +1724,7 @@ pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbo | ... | @@ -1398,7 +1724,7 @@ pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbo |
| 1398 | sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity(); | 1724 | sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity(); |
| 1399 | coff.synth_prog_node.increaseEstimatedTotalItems(1); | 1725 | coff.synth_prog_node.increaseEstimatedTotalItems(1); |
| 1400 | } | 1726 | } |
| 1401 | return sym_gop.value_ptr.*; | 1727 | return sym_gop; |
| 1402 | } | 1728 | } |
| 1403 | | 1729 | |
| 1404 | fn navSection( | 1730 | fn navSection( |
| ... | @@ -1500,10 +1826,187 @@ pub fn getVAddr(coff: *Coff, reloc_info: link.File.RelocInfo, target_si: Symbol. | ... | @@ -1500,10 +1826,187 @@ pub fn getVAddr(coff: *Coff, reloc_info: link.File.RelocInfo, target_si: Symbol. |
| 1500 | .I386 => .{ .I386 = .DIR32 }, | 1826 | .I386 => .{ .I386 = .DIR32 }, |
| 1501 | }, | 1827 | }, |
| 1502 | ); | 1828 | ); |
| 1503 | return coff.optionalHeaderField(.image_base) + target_si.get(coff).rva; | 1829 | |
| | 1830 | var vaddr: u64 = target_si.get(coff).rva; |
| | 1831 | if (coff.isImage()) vaddr += coff.optionalHeaderField(.image_base); |
| | 1832 | return vaddr; |
| | 1833 | } |
| | 1834 | |
| | 1835 | /// Caller guarantees there is capacity for one member and two nodes |
| | 1836 | fn addMemberAssumeCapacity(coff: *Coff, kind: Member.Kind, size: usize) !Member.Index { |
| | 1837 | const comp = coff.base.comp; |
| | 1838 | const gpa = comp.gpa; |
| | 1839 | |
| | 1840 | // TODO: These two nodes could to be inside a movable node? Only if coff or import |
| | 1841 | |
| | 1842 | const header_ni = try coff.mf.addLastChildNode(gpa, Node.known.file, .{ |
| | 1843 | .size = @sizeOf(std.coff.ArchiveMemberHeader), |
| | 1844 | .alignment = .@"2", |
| | 1845 | .fixed = true, |
| | 1846 | .moved = true, |
| | 1847 | }); |
| | 1848 | |
| | 1849 | const content_ni = try coff.mf.addLastChildNode(gpa, Node.known.file, .{ |
| | 1850 | // The actual alignment required by the spec is 2, but to allow aligned access to |
| | 1851 | // the various COFF data structures in-place during linking we overalign |
| | 1852 | .alignment = switch (kind) { |
| | 1853 | .coff => .@"4", |
| | 1854 | else => .@"2", |
| | 1855 | }, |
| | 1856 | .size = size, |
| | 1857 | .resized = size > 0, |
| | 1858 | .fixed = true, |
| | 1859 | }); |
| | 1860 | |
| | 1861 | const mi: Member.Index = @enumFromInt(coff.members.items.len); |
| | 1862 | coff.members.appendAssumeCapacity(.{ |
| | 1863 | .kind = kind, |
| | 1864 | .header_ni = header_ni, |
| | 1865 | .content_ni = content_ni, |
| | 1866 | .symbol_offsets = .empty, |
| | 1867 | }); |
| | 1868 | |
| | 1869 | coff.nodes.appendAssumeCapacity(.{ .archive_member_header = mi }); |
| | 1870 | coff.nodes.appendAssumeCapacity(.{ .archive_member = mi }); |
| | 1871 | |
| | 1872 | switch (kind) { |
| | 1873 | .first_linker, .second_linker, .longnames => {}, |
| | 1874 | else => { |
| | 1875 | const new_num_members = coff.members.items.len - Member.Index.known_count; |
| | 1876 | coff.targetStore( |
| | 1877 | coff.secondLinkerMemberNumMembersPtr(), |
| | 1878 | @intCast(new_num_members), |
| | 1879 | ); |
| | 1880 | |
| | 1881 | const old_size = Node.known.second_linker_member.location(&coff.mf).resolve(&coff.mf)[1]; |
| | 1882 | const old_header_size = new_num_members * @sizeOf(u32); |
| | 1883 | const trailing_size = old_size - old_header_size; |
| | 1884 | try Node.known.second_linker_member.resize(&coff.mf, gpa, old_size + @sizeOf(u32)); |
| | 1885 | |
| | 1886 | const slice = Node.known.second_linker_member.slice(&coff.mf); |
| | 1887 | @memmove( |
| | 1888 | slice[old_header_size + @sizeOf(u32) ..][0..trailing_size], |
| | 1889 | slice[old_header_size..][0..trailing_size], |
| | 1890 | ); |
| | 1891 | |
| | 1892 | // Offset will be written by flushMoved on header_ni |
| | 1893 | }, |
| | 1894 | } |
| | 1895 | |
| | 1896 | switch (kind) { |
| | 1897 | .first_linker, |
| | 1898 | .longnames, |
| | 1899 | .import, |
| | 1900 | => {}, |
| | 1901 | .second_linker, |
| | 1902 | .coff, |
| | 1903 | => { |
| | 1904 | try coff.pending_members.ensureTotalCapacity( |
| | 1905 | gpa, |
| | 1906 | coff.pending_members.capacity() + 1, |
| | 1907 | ); |
| | 1908 | }, |
| | 1909 | } |
| | 1910 | |
| | 1911 | return mi; |
| | 1912 | } |
| | 1913 | |
| | 1914 | fn appendMemberSymbolString( |
| | 1915 | coff: *Coff, |
| | 1916 | strings_ni: MappedFile.Node.Index, |
| | 1917 | new_size: u64, |
| | 1918 | name: []const u8, |
| | 1919 | offset: u64, |
| | 1920 | ) !void { |
| | 1921 | try strings_ni.resize(&coff.mf, coff.base.comp.gpa, new_size); |
| | 1922 | const name_slice = strings_ni.slice(&coff.mf)[offset..][0 .. name.len + 1]; |
| | 1923 | @memcpy(name_slice[0..name.len], name); |
| | 1924 | name_slice[name.len] = 0; |
| | 1925 | } |
| | 1926 | |
| | 1927 | fn addMemberSymbol( |
| | 1928 | coff: *Coff, |
| | 1929 | name: String, |
| | 1930 | mi: Member.Index, |
| | 1931 | si: Symbol.Index, |
| | 1932 | ) !void { |
| | 1933 | const gpa = coff.base.comp.gpa; |
| | 1934 | const member = mi.get(coff); |
| | 1935 | assert(member.kind == .coff); |
| | 1936 | |
| | 1937 | const gop = try member.symbol_offsets.getOrPut(gpa, si); |
| | 1938 | if (gop.found_existing) return; |
| | 1939 | |
| | 1940 | // TODO: Detect duplicate names (ie. a name used by a symbol in another member, not the zcu since those already go through globals) |
| | 1941 | |
| | 1942 | const symbol_index = blk: { |
| | 1943 | const num_symbols_ptr = coff.firstLinkerMemberNumSymbolsPtr(); |
| | 1944 | const num_symbols = std.mem.toNative(u32, num_symbols_ptr.*, .big); |
| | 1945 | num_symbols_ptr.* = std.mem.nativeTo(u32, num_symbols + 1, .big); |
| | 1946 | break :blk num_symbols; |
| | 1947 | }; |
| | 1948 | |
| | 1949 | gop.value_ptr.* = symbol_index; |
| | 1950 | const name_slice = name.toSlice(coff); |
| | 1951 | |
| | 1952 | // Linker member fields are not modeled as nodes because MappedFile |
| | 1953 | // can't guarantee that they will be tightly packed after resizing |
| | 1954 | |
| | 1955 | const new_string_table_size = coff.lib_string_len + name_slice.len + 1; |
| | 1956 | defer coff.lib_string_len = new_string_table_size; |
| | 1957 | |
| | 1958 | { |
| | 1959 | const old_header_size = @sizeOf(u32) + symbol_index * @sizeOf(u32); |
| | 1960 | const new_header_size = old_header_size + @sizeOf(u32); |
| | 1961 | try Node.known.first_linker_member.resize(&coff.mf, gpa, new_header_size + new_string_table_size); |
| | 1962 | |
| | 1963 | const slice = Node.known.first_linker_member.slice(&coff.mf); |
| | 1964 | @memmove(slice[new_header_size..][0..coff.lib_string_len], slice[old_header_size..][0..coff.lib_string_len]); |
| | 1965 | @memcpy(slice[new_header_size + coff.lib_string_len ..][0 .. name_slice.len + 1], name_slice[0 .. name_slice.len + 1]); |
| | 1966 | |
| | 1967 | // New offset entry is written in flushMember |
| | 1968 | } |
| | 1969 | |
| | 1970 | { |
| | 1971 | const num_members = coff.targetLoad(coff.secondLinkerMemberNumMembersPtr()); |
| | 1972 | const old_header_size = 2 * @sizeOf(u32) + num_members * @sizeOf(u32) + symbol_index * @sizeOf(u16); |
| | 1973 | const new_header_size = old_header_size + @sizeOf(u16); |
| | 1974 | try Node.known.second_linker_member.resize(&coff.mf, gpa, new_header_size + new_string_table_size); |
| | 1975 | |
| | 1976 | const needs_sort = if (coff.lib_string_table.items.len > 0) |
| | 1977 | std.mem.lessThan( |
| | 1978 | u8, |
| | 1979 | name_slice, |
| | 1980 | coff.lib_string_table.items[coff.lib_string_table.items.len - 1].toSlice(coff), |
| | 1981 | ) |
| | 1982 | else |
| | 1983 | false; |
| | 1984 | |
| | 1985 | try coff.lib_string_table.append(gpa, name); |
| | 1986 | |
| | 1987 | const slice = Node.known.second_linker_member.slice(&coff.mf); |
| | 1988 | const num_symbols_ptr: *u32 = @ptrCast(@alignCast(slice[@sizeOf(u32) + num_members * @sizeOf(u32) ..])); |
| | 1989 | coff.targetStore(num_symbols_ptr, symbol_index + 1); |
| | 1990 | |
| | 1991 | if (needs_sort) { |
| | 1992 | // The entire string table is rebuilt in flushMember after sorting |
| | 1993 | coff.pending_members.putAssumeCapacity(Member.Index.second, {}); |
| | 1994 | } else { |
| | 1995 | @memmove(slice[new_header_size..][0..coff.lib_string_len], slice[old_header_size..][0..coff.lib_string_len]); |
| | 1996 | @memcpy(slice[new_header_size + coff.lib_string_len ..][0 .. name_slice.len + 1], name_slice[0 .. name_slice.len + 1]); |
| | 1997 | } |
| | 1998 | |
| | 1999 | // Indices in this table are 1-based |
| | 2000 | const index_ptr: *u16 = @ptrCast(@alignCast(slice[old_header_size..])); |
| | 2001 | coff.targetStore(index_ptr, @intCast(@intFromEnum(mi) - Member.Index.known_count + 1)); |
| | 2002 | } |
| | 2003 | |
| | 2004 | coff.pending_members.putAssumeCapacity(mi, {}); |
| 1504 | } | 2005 | } |
| 1505 | | 2006 | |
| 1506 | fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags) !Symbol.Index { | 2007 | fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags) !Symbol.Index { |
| | 2008 | assert(coff.base.comp.zcu != null); |
| | 2009 | |
| 1507 | const gpa = coff.base.comp.gpa; | 2010 | const gpa = coff.base.comp.gpa; |
| 1508 | try coff.nodes.ensureUnusedCapacity(gpa, 1); | 2011 | try coff.nodes.ensureUnusedCapacity(gpa, 1); |
| 1509 | try coff.image_section_table.ensureUnusedCapacity(gpa, 1); | 2012 | try coff.image_section_table.ensureUnusedCapacity(gpa, 1); |
| ... | @@ -1518,21 +2021,34 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags | ... | @@ -1518,21 +2021,34 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags |
| 1518 | gpa, | 2021 | gpa, |
| 1519 | @sizeOf(std.coff.SectionHeader) * section_table_len, | 2022 | @sizeOf(std.coff.SectionHeader) * section_table_len, |
| 1520 | ); | 2023 | ); |
| 1521 | const ni = try coff.mf.addLastChildNode(gpa, .root, .{ | 2024 | |
| 1522 | .alignment = coff.mf.flags.block_size, | 2025 | const parent_ni, const alignment = if (coff.isArchive()) |
| | 2026 | .{ Node.known.zcu_member, .@"1" } |
| | 2027 | else |
| | 2028 | .{ Node.known.file, coff.mf.flags.block_size }; |
| | 2029 | |
| | 2030 | const ni = try coff.mf.addLastChildNode(gpa, parent_ni, .{ |
| | 2031 | .alignment = alignment, |
| 1523 | .moved = true, | 2032 | .moved = true, |
| 1524 | .bubbles_moved = false, | 2033 | .bubbles_moved = false, |
| 1525 | }); | 2034 | }); |
| | 2035 | |
| 1526 | const si = coff.addSymbolAssumeCapacity(); | 2036 | const si = coff.addSymbolAssumeCapacity(); |
| 1527 | coff.image_section_table.appendAssumeCapacity(si); | 2037 | coff.image_section_table.appendAssumeCapacity(si); |
| 1528 | coff.nodes.appendAssumeCapacity(.{ .image_section = si }); | 2038 | coff.nodes.appendAssumeCapacity(.{ .image_section = si }); |
| 1529 | const section_table = coff.sectionTableSlice(); | 2039 | const section_table = coff.sectionTableSlice(); |
| 1530 | const virtual_size = coff.optionalHeaderField(.section_alignment); | 2040 | |
| 1531 | const rva: u32 = switch (section_index) { | 2041 | const virtual_size, const rva = if (coff.isImage()) block: { |
| 1532 | 0 => @intCast(Node.known.header.location(&coff.mf).resolve(&coff.mf)[1]), | 2042 | const virtual_size = coff.optionalHeaderField(.section_alignment); |
| 1533 | else => coff.image_section_table.items[section_index - 1].get(coff).rva + | 2043 | const rva: u32 = switch (section_index) { |
| 1534 | coff.targetLoad(&section_table[section_index - 1].virtual_size), | 2044 | 0 => @intCast(Node.known.header.location(&coff.mf).resolve(&coff.mf)[1]), |
| 1535 | }; | 2045 | else => coff.image_section_table.items[section_index - 1].get(coff).rva + |
| | 2046 | coff.targetLoad(&section_table[section_index - 1].virtual_size), |
| | 2047 | }; |
| | 2048 | |
| | 2049 | break :block .{ virtual_size, rva }; |
| | 2050 | } else .{ 0, 0 }; |
| | 2051 | |
| 1536 | { | 2052 | { |
| 1537 | const sym = si.get(coff); | 2053 | const sym = si.get(coff); |
| 1538 | sym.ni = ni; | 2054 | sym.ni = ni; |
| ... | @@ -1556,12 +2072,16 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags | ... | @@ -1556,12 +2072,16 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags |
| 1556 | @memset(section.name[name.len..], 0); | 2072 | @memset(section.name[name.len..], 0); |
| 1557 | if (coff.targetEndian() != native_endian) | 2073 | if (coff.targetEndian() != native_endian) |
| 1558 | std.mem.byteSwapAllFields(std.coff.SectionHeader, section); | 2074 | std.mem.byteSwapAllFields(std.coff.SectionHeader, section); |
| 1559 | switch (coff.optionalHeaderPtr()) { | 2075 | |
| 1560 | inline else => |optional_header| coff.targetStore( | 2076 | if (coff.isImage()) { |
| 1561 | &optional_header.size_of_image, | 2077 | switch (coff.optionalHeaderPtr()) { |
| 1562 | @intCast(rva + virtual_size), | 2078 | inline else => |optional_header| coff.targetStore( |
| 1563 | ), | 2079 | &optional_header.size_of_image, |
| | 2080 | @intCast(rva + virtual_size), |
| | 2081 | ), |
| | 2082 | } |
| 1564 | } | 2083 | } |
| | 2084 | |
| 1565 | return si; | 2085 | return si; |
| 1566 | } | 2086 | } |
| 1567 | | 2087 | |
| ... | @@ -1686,6 +2206,16 @@ pub fn addReloc( | ... | @@ -1686,6 +2206,16 @@ pub fn addReloc( |
| 1686 | target.target_relocs = ri; | 2206 | target.target_relocs = ri; |
| 1687 | } | 2207 | } |
| 1688 | | 2208 | |
| | 2209 | pub fn loadInput(coff: *Coff, input: link.Input) void { |
| | 2210 | _ = coff; |
| | 2211 | switch (input) { |
| | 2212 | .dso_exact => unreachable, |
| | 2213 | inline else => |i, tag| { |
| | 2214 | log.debug("loadInput({s}: {f})", .{ @tagName(tag), i.path.fmtEscapeString() }); |
| | 2215 | }, |
| | 2216 | } |
| | 2217 | } |
| | 2218 | |
| 1689 | pub fn prelink(coff: *Coff, prog_node: std.Progress.Node) link.Error!void { | 2219 | pub fn prelink(coff: *Coff, prog_node: std.Progress.Node) link.Error!void { |
| 1690 | _ = coff; | 2220 | _ = coff; |
| 1691 | _ = prog_node; | 2221 | _ = prog_node; |
| ... | @@ -1976,6 +2506,11 @@ pub fn flush( | ... | @@ -1976,6 +2506,11 @@ pub fn flush( |
| 1976 | _ = prog_node; | 2506 | _ = prog_node; |
| 1977 | while (try coff.idle(tid)) {} | 2507 | while (try coff.idle(tid)) {} |
| 1978 | | 2508 | |
| | 2509 | // TODO: Second linker member symbol tables are built here |
| | 2510 | if (isArchive(coff)) { |
| | 2511 | //Member.Index.second.get(coff).content_ni; |
| | 2512 | } |
| | 2513 | |
| 1979 | const comp = coff.base.comp; | 2514 | const comp = coff.base.comp; |
| 1980 | | 2515 | |
| 1981 | // Implib generation should instead be done via building a MappedFile progressively | 2516 | // Implib generation should instead be done via building a MappedFile progressively |
| ... | @@ -1985,8 +2520,8 @@ pub fn flush( | ... | @@ -1985,8 +2520,8 @@ pub fn flush( |
| 1985 | | 2520 | |
| 1986 | // hack for stage2_x86_64 + coff | 2521 | // hack for stage2_x86_64 + coff |
| 1987 | if (comp.compiler_rt_dyn_lib) |crt_file| { | 2522 | if (comp.compiler_rt_dyn_lib) |crt_file| { |
| 1988 | const gpa = comp.gpa; | | |
| 1989 | const io = comp.io; | 2523 | const io = comp.io; |
| | 2524 | const gpa = comp.gpa; |
| 1990 | | 2525 | |
| 1991 | const compiler_rt_sub_path = try std.fs.path.join(gpa, &.{ | 2526 | const compiler_rt_sub_path = try std.fs.path.join(gpa, &.{ |
| 1992 | std.fs.path.dirname(coff.base.emit.sub_path) orelse "", | 2527 | std.fs.path.dirname(coff.base.emit.sub_path) orelse "", |
| ... | @@ -2002,6 +2537,14 @@ pub fn flush( | ... | @@ -2002,6 +2537,14 @@ pub fn flush( |
| 2002 | .{}, | 2537 | .{}, |
| 2003 | ) catch |err| return comp.link_diags.fail("copy '{s}' failed: {t}", .{ compiler_rt_sub_path, err }); | 2538 | ) catch |err| return comp.link_diags.fail("copy '{s}' failed: {t}", .{ compiler_rt_sub_path, err }); |
| 2004 | } | 2539 | } |
| | 2540 | |
| | 2541 | coff.mf.flush() catch |err| switch (err) { |
| | 2542 | error.Canceled => |e| return e, |
| | 2543 | else => |e| return comp.link_diags.fail("flush write failed: {t}", .{e}), |
| | 2544 | }; |
| | 2545 | |
| | 2546 | coff.dumpStderr(tid) catch |err| |
| | 2547 | return comp.link_diags.fail("dumping link snapshot failed: {t}", .{err}); |
| 2005 | } | 2548 | } |
| 2006 | | 2549 | |
| 2007 | pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { | 2550 | pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| ... | @@ -2080,7 +2623,13 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { | ... | @@ -2080,7 +2623,13 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 2080 | break :task; | 2623 | break :task; |
| 2081 | } else coff.mf.update_prog_node.completeOne(); | 2624 | } else coff.mf.update_prog_node.completeOne(); |
| 2082 | } | 2625 | } |
| | 2626 | while (coff.pending_members.pop()) |pending_mi| { |
| | 2627 | // TODO: Prog node |
| | 2628 | try coff.flushMember(pending_mi.key); |
| | 2629 | break :task; |
| | 2630 | } |
| 2083 | if (coff.export_table.pending_sort) { | 2631 | if (coff.export_table.pending_sort) { |
| | 2632 | // TODO: Prog node |
| 2084 | coff.export_table.pending_sort = false; | 2633 | coff.export_table.pending_sort = false; |
| 2085 | coff.flushExportsSort(); | 2634 | coff.flushExportsSort(); |
| 2086 | break :task; | 2635 | break :task; |
| ... | @@ -2090,6 +2639,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { | ... | @@ -2090,6 +2639,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 2090 | if (coff.globals.count() > coff.global_pending_index) return true; | 2639 | if (coff.globals.count() > coff.global_pending_index) return true; |
| 2091 | for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; | 2640 | for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; |
| 2092 | if (coff.mf.updates.items.len > 0) return true; | 2641 | if (coff.mf.updates.items.len > 0) return true; |
| | 2642 | if (coff.pending_members.count() > 0) return true; |
| 2093 | if (coff.export_table.pending_sort) return true; | 2643 | if (coff.export_table.pending_sort) return true; |
| 2094 | return false; | 2644 | return false; |
| 2095 | } | 2645 | } |
| ... | @@ -2183,6 +2733,10 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void { | ... | @@ -2183,6 +2733,10 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void { |
| 2183 | const gpa = zcu.gpa; | 2733 | const gpa = zcu.gpa; |
| 2184 | const gn = gmi.globalName(coff); | 2734 | const gn = gmi.globalName(coff); |
| 2185 | | 2735 | |
| | 2736 | // TODO: We still need to emit a reloc for the __imp_Name symbol? |
| | 2737 | |
| | 2738 | if (!coff.isImage()) return; |
| | 2739 | |
| 2186 | if (gn.lib_name.toSlice(coff)) |lib_name| { | 2740 | if (gn.lib_name.toSlice(coff)) |lib_name| { |
| 2187 | const name = gn.name.toSlice(coff); | 2741 | const name = gn.name.toSlice(coff); |
| 2188 | try coff.nodes.ensureUnusedCapacity(gpa, 4); | 2742 | try coff.nodes.ensureUnusedCapacity(gpa, 4); |
| ... | @@ -2394,19 +2948,44 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { | ... | @@ -2394,19 +2948,44 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { |
| 2394 | } | 2948 | } |
| 2395 | | 2949 | |
| 2396 | fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { | 2950 | fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| | 2951 | log.debug("flushMoved({s})", .{@tagName(coff.getNode(ni))}); |
| 2397 | switch (coff.getNode(ni)) { | 2952 | switch (coff.getNode(ni)) { |
| 2398 | .file, | 2953 | .file, |
| 2399 | .header, | 2954 | .header, |
| 2400 | .signature, | 2955 | .signature, |
| | 2956 | => unreachable, |
| 2401 | .coff_header, | 2957 | .coff_header, |
| 2402 | .optional_header, | 2958 | .optional_header, |
| 2403 | .data_directories, | 2959 | .data_directories, |
| 2404 | .section_table, | 2960 | .section_table, |
| 2405 | => unreachable, | 2961 | .placeholder, |
| 2406 | .image_section => |si| return coff.targetStore( | 2962 | => if (!coff.isArchive()) unreachable, |
| 2407 | &si.get(coff).section_number.header(coff).pointer_to_raw_data, | 2963 | .archive_member_header => |mi| { |
| 2408 | @intCast(ni.fileLocation(&coff.mf, false).offset), | 2964 | const member = mi.get(coff); |
| 2409 | ), | 2965 | switch (member.kind) { |
| | 2966 | .first_linker, .second_linker, .longnames => {}, |
| | 2967 | else => coff.targetStore( |
| | 2968 | &coff.secondLinkerMemberOffsetsSlice()[@intFromEnum(mi) - Member.Index.known_count], |
| | 2969 | @intCast(ni.fileLocation(&coff.mf, false).offset), |
| | 2970 | ), |
| | 2971 | } |
| | 2972 | |
| | 2973 | if (member.kind == .coff) |
| | 2974 | try coff.pending_members.put(coff.base.comp.gpa, mi, {}); |
| | 2975 | }, |
| | 2976 | .archive_member, |
| | 2977 | => {}, |
| | 2978 | .image_section => |si| { |
| | 2979 | const file_offset = if (isArchive(coff)) |
| | 2980 | si.get(coff).ni.location(&coff.mf).resolve(&coff.mf)[0] |
| | 2981 | else |
| | 2982 | ni.fileLocation(&coff.mf, false).offset; |
| | 2983 | |
| | 2984 | return coff.targetStore( |
| | 2985 | &si.get(coff).section_number.header(coff).pointer_to_raw_data, |
| | 2986 | @intCast(file_offset), |
| | 2987 | ); |
| | 2988 | }, |
| 2410 | .import_directory_table => coff.targetStore( | 2989 | .import_directory_table => coff.targetStore( |
| 2411 | &coff.dataDirectoryPtr(.IMPORT).virtual_address, | 2990 | &coff.dataDirectoryPtr(.IMPORT).virtual_address, |
| 2412 | coff.computeNodeRva(ni), | 2991 | coff.computeNodeRva(ni), |
| ... | @@ -2523,32 +3102,69 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { | ... | @@ -2523,32 +3102,69 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 2523 | | 3102 | |
| 2524 | fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { | 3103 | fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 2525 | _, const size = ni.location(&coff.mf).resolve(&coff.mf); | 3104 | _, const size = ni.location(&coff.mf).resolve(&coff.mf); |
| | 3105 | log.debug("flushResized({s}, 0x{x})", .{ @tagName(coff.getNode(ni)), size }); |
| | 3106 | |
| 2526 | switch (coff.getNode(ni)) { | 3107 | switch (coff.getNode(ni)) { |
| 2527 | .file => {}, | 3108 | .file => { |
| | 3109 | if (coff.isArchive() and coff.members.items.len > 0) { |
| | 3110 | const last_member = coff.members.items[coff.members.items.len - 1]; |
| | 3111 | assert(Node.known.file.reverseChildren(&coff.mf).ni == last_member.content_ni); |
| | 3112 | try coff.flushResized(last_member.content_ni); |
| | 3113 | } |
| | 3114 | }, |
| 2528 | .header => { | 3115 | .header => { |
| 2529 | switch (coff.optionalHeaderPtr()) { | 3116 | if (coff.isImage()) { |
| 2530 | inline else => |optional_header| coff.targetStore( | 3117 | switch (coff.optionalHeaderPtr()) { |
| 2531 | &optional_header.size_of_headers, | 3118 | inline else => |optional_header| coff.targetStore( |
| 2532 | @intCast(size), | 3119 | &optional_header.size_of_headers, |
| 2533 | ), | 3120 | @intCast(size), |
| | 3121 | ), |
| | 3122 | } |
| | 3123 | |
| | 3124 | if (size > coff.image_section_table.items[0].get(coff).rva) try coff.virtualSlide( |
| | 3125 | 0, |
| | 3126 | std.mem.alignForward( |
| | 3127 | u32, |
| | 3128 | @intCast(size * 4), |
| | 3129 | coff.optionalHeaderField(.section_alignment), |
| | 3130 | ), |
| | 3131 | ); |
| 2534 | } | 3132 | } |
| 2535 | if (size > coff.image_section_table.items[0].get(coff).rva) try coff.virtualSlide( | | |
| 2536 | 0, | | |
| 2537 | std.mem.alignForward( | | |
| 2538 | u32, | | |
| 2539 | @intCast(size * 4), | | |
| 2540 | coff.optionalHeaderField(.section_alignment), | | |
| 2541 | ), | | |
| 2542 | ); | | |
| 2543 | }, | 3133 | }, |
| 2544 | .signature, .coff_header, .optional_header, .data_directories => unreachable, | 3134 | .signature, |
| | 3135 | .archive_member_header, |
| | 3136 | => unreachable, |
| | 3137 | .archive_member => |mi| { |
| | 3138 | const content_ni = mi.get(coff).content_ni; |
| | 3139 | const next_ni = content_ni.next(&coff.mf); |
| | 3140 | const offset, _ = content_ni.location(&coff.mf).resolve(&coff.mf); |
| | 3141 | const next_offset = switch (next_ni) { |
| | 3142 | .none => offset: { |
| | 3143 | assert(content_ni.parent(&coff.mf) == Node.known.file); |
| | 3144 | // This must take into account the final file size. If there are trailing |
| | 3145 | // bytes, they will be expected to contain another valid member header |
| | 3146 | break :offset coff.mf.memory_map.memory.len; |
| | 3147 | }, |
| | 3148 | else => offset: { |
| | 3149 | assert(coff.getNode(next_ni) == .archive_member_header); |
| | 3150 | break :offset next_ni.location(&coff.mf).resolve(&coff.mf)[0]; |
| | 3151 | }, |
| | 3152 | }; |
| | 3153 | |
| | 3154 | // Not inserting IMAGE_ARCHIVE_PAD `\n` byte here, because we are expanding to full size |
| | 3155 | Member.storeHeaderDecimalStr(&mi.get(coff).headerPtr(coff).size, next_offset - offset); |
| | 3156 | }, |
| | 3157 | .coff_header, |
| | 3158 | .optional_header, |
| | 3159 | .data_directories, |
| | 3160 | => unreachable, |
| 2545 | .section_table => {}, | 3161 | .section_table => {}, |
| 2546 | .image_section => |si| { | 3162 | .image_section => |si| { |
| 2547 | const sym = si.get(coff); | 3163 | const sym = si.get(coff); |
| 2548 | const section_index = sym.section_number.toIndex(); | 3164 | const section_index = sym.section_number.toIndex(); |
| 2549 | const section = &coff.sectionTableSlice()[section_index]; | 3165 | const section = &coff.sectionTableSlice()[section_index]; |
| 2550 | coff.targetStore(&section.size_of_raw_data, @intCast(size)); | 3166 | coff.targetStore(&section.size_of_raw_data, @intCast(size)); |
| 2551 | if (size > coff.targetLoad(&section.virtual_size)) { | 3167 | if (coff.isImage() and size > coff.targetLoad(&section.virtual_size)) { |
| 2552 | const virtual_size = std.mem.alignForward( | 3168 | const virtual_size = std.mem.alignForward( |
| 2553 | u32, | 3169 | u32, |
| 2554 | @intCast(size * 4), | 3170 | @intCast(size * 4), |
| ... | @@ -2562,16 +3178,87 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { | ... | @@ -2562,16 +3178,87 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 2562 | &coff.dataDirectoryPtr(.IMPORT).size, | 3178 | &coff.dataDirectoryPtr(.IMPORT).size, |
| 2563 | @intCast(size), | 3179 | @intCast(size), |
| 2564 | ), | 3180 | ), |
| 2565 | .import_lookup_table, .import_address_table, .import_hint_name_table => {}, | 3181 | .import_lookup_table, |
| 2566 | .export_directory_table => coff.targetStore( | 3182 | .import_address_table, |
| 2567 | &coff.dataDirectoryPtr(.EXPORT).size, | 3183 | .import_hint_name_table, |
| 2568 | @intCast(size), | 3184 | => {}, |
| 2569 | ), | 3185 | .export_directory_table => unreachable, |
| 2570 | .export_address_table, .export_name_pointer_table, .export_ordinal_table, .export_name_table => {}, | 3186 | .export_address_table, |
| | 3187 | .export_name_pointer_table, |
| | 3188 | .export_ordinal_table, |
| | 3189 | .export_name_table, |
| | 3190 | => {}, |
| 2571 | inline .pseudo_section, | 3191 | inline .pseudo_section, |
| 2572 | .object_section, | 3192 | .object_section, |
| 2573 | => |smi| smi.symbol(coff).get(coff).size = @intCast(size), | 3193 | => |smi, tag| { |
| 2574 | .global, .nav, .uav, .lazy_code, .lazy_const_data => {}, | 3194 | if (tag == .pseudo_section and smi.name(coff) == .@".edata") { |
| | 3195 | coff.targetStore( |
| | 3196 | &coff.dataDirectoryPtr(.EXPORT).size, |
| | 3197 | @intCast(size), |
| | 3198 | ); |
| | 3199 | } |
| | 3200 | |
| | 3201 | smi.symbol(coff).get(coff).size = @intCast(size); |
| | 3202 | }, |
| | 3203 | .global, |
| | 3204 | .nav, |
| | 3205 | .uav, |
| | 3206 | .lazy_code, |
| | 3207 | .lazy_const_data, |
| | 3208 | => {}, |
| | 3209 | .placeholder => unreachable, |
| | 3210 | } |
| | 3211 | } |
| | 3212 | |
| | 3213 | fn flushMember(coff: *Coff, mi: Member.Index) !void { |
| | 3214 | const member = mi.get(coff); |
| | 3215 | switch (member.kind) { |
| | 3216 | .first_linker, |
| | 3217 | .longnames, |
| | 3218 | .import, |
| | 3219 | => unreachable, |
| | 3220 | .second_linker => { |
| | 3221 | const Context = struct { |
| | 3222 | coff: *Coff, |
| | 3223 | indices: []u16, |
| | 3224 | strings: []String, |
| | 3225 | |
| | 3226 | pub fn lessThan(ctx: @This(), lhs: usize, rhs: usize) bool { |
| | 3227 | return std.mem.lessThan( |
| | 3228 | u8, |
| | 3229 | ctx.strings[lhs].toSlice(ctx.coff), |
| | 3230 | ctx.strings[rhs].toSlice(ctx.coff), |
| | 3231 | ); |
| | 3232 | } |
| | 3233 | |
| | 3234 | pub fn swap(ctx: @This(), lhs: usize, rhs: usize) void { |
| | 3235 | std.mem.swap(u16, &ctx.indices[lhs], &ctx.indices[rhs]); |
| | 3236 | std.mem.swap(String, &ctx.strings[lhs], &ctx.strings[rhs]); |
| | 3237 | } |
| | 3238 | }; |
| | 3239 | |
| | 3240 | std.sort.pdqContext(0, coff.lib_string_table.items.len, Context{ |
| | 3241 | .coff = coff, |
| | 3242 | .indices = coff.secondLinkerMemberIndicesSlice(), |
| | 3243 | .strings = coff.lib_string_table.items, |
| | 3244 | }); |
| | 3245 | |
| | 3246 | var offset: u64 = 0; |
| | 3247 | |
| | 3248 | var string_table = coff.secondLinkerMemberStringsSlice(); |
| | 3249 | for (coff.lib_string_table.items) |string| { |
| | 3250 | const str = string.toSlice(coff); |
| | 3251 | @memcpy(string_table[offset..][0..str.len], str); |
| | 3252 | string_table[offset + str.len] = 0; |
| | 3253 | offset += str.len + 1; |
| | 3254 | } |
| | 3255 | }, |
| | 3256 | .coff => { |
| | 3257 | const file_offset: u32 = @intCast(member.header_ni.fileLocation(&coff.mf, false).offset); |
| | 3258 | const first_linker_offsets = coff.firstLinkerMemberOffsetsSlice(); |
| | 3259 | for (member.symbol_offsets.values()) |offset_index| |
| | 3260 | first_linker_offsets[offset_index] = std.mem.nativeTo(u32, file_offset, .big); |
| | 3261 | }, |
| 2575 | } | 3262 | } |
| 2576 | } | 3263 | } |
| 2577 | | 3264 | |
| ... | @@ -2666,12 +3353,14 @@ fn updateExportsInner( | ... | @@ -2666,12 +3353,14 @@ fn updateExportsInner( |
| 2666 | ))), | 3353 | ))), |
| 2667 | }; | 3354 | }; |
| 2668 | while (try coff.idle(pt.tid)) {} | 3355 | while (try coff.idle(pt.tid)) {} |
| | 3356 | |
| 2669 | const exported_ni = exported_si.node(coff); | 3357 | const exported_ni = exported_si.node(coff); |
| 2670 | const exported_sym = exported_si.get(coff); | 3358 | const exported_sym = exported_si.get(coff); |
| 2671 | for (export_indices) |export_index| { | 3359 | for (export_indices) |export_index| { |
| 2672 | const @"export" = export_index.ptr(zcu); | 3360 | const @"export" = export_index.ptr(zcu); |
| 2673 | const name = @"export".opts.name.toSlice(ip); | 3361 | const name = @"export".opts.name.toSlice(ip); |
| 2674 | const export_si = try coff.globalSymbol(name, null); | 3362 | const symbol_gop = try coff.getOrPutGlobalSymbol(name, null); |
| | 3363 | const export_si = symbol_gop.value_ptr.*; |
| 2675 | const export_sym = export_si.get(coff); | 3364 | const export_sym = export_si.get(coff); |
| 2676 | export_sym.ni = exported_ni; | 3365 | export_sym.ni = exported_ni; |
| 2677 | export_sym.rva = exported_sym.rva; | 3366 | export_sym.rva = exported_sym.rva; |
| ... | @@ -2687,6 +3376,13 @@ fn updateExportsInner( | ... | @@ -2687,6 +3376,13 @@ fn updateExportsInner( |
| 2687 | std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, tls_directory); | 3376 | std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, tls_directory); |
| 2688 | } | 3377 | } |
| 2689 | | 3378 | |
| | 3379 | if (coff.isArchive()) |
| | 3380 | try coff.addMemberSymbol( |
| | 3381 | symbol_gop.key_ptr.*.name, |
| | 3382 | coff.getNode(Node.known.zcu_member).archive_member, |
| | 3383 | export_si, |
| | 3384 | ); |
| | 3385 | |
| 2690 | if (coff.export_table.ni == .none) continue; | 3386 | if (coff.export_table.ni == .none) continue; |
| 2691 | | 3387 | |
| 2692 | const entries_ctx = ExportTable.Adapter{ .coff = coff }; | 3388 | const entries_ctx = ExportTable.Adapter{ .coff = coff }; |
| ... | @@ -2703,7 +3399,7 @@ fn updateExportsInner( | ... | @@ -2703,7 +3399,7 @@ fn updateExportsInner( |
| 2703 | if (export_count > std.math.maxInt(@FieldType(std.coff.ExportDirectoryTable, "number_of_entries"))) | 3399 | if (export_count > std.math.maxInt(@FieldType(std.coff.ExportDirectoryTable, "number_of_entries"))) |
| 2704 | return coff.base.comp.link_diags.fail("exceeded maximum number of exports", .{}); | 3400 | return coff.base.comp.link_diags.fail("exceeded maximum number of exports", .{}); |
| 2705 | | 3401 | |
| 2706 | const name_index = coff.export_table.name_table_ni.fileLocation(&coff.mf, true).size; | 3402 | const name_index: u64 = coff.export_table.name_table_ni.location(&coff.mf).resolve(&coff.mf)[1]; |
| 2707 | const new_name_table_size = name_index + name.len + 1; | 3403 | const new_name_table_size = name_index + name.len + 1; |
| 2708 | if (new_name_table_size > std.math.maxInt(@FieldType(ExportTable.Entry, "name_index"))) | 3404 | if (new_name_table_size > std.math.maxInt(@FieldType(ExportTable.Entry, "name_index"))) |
| 2709 | return coff.base.comp.link_diags.fail("exports name table limit reached", .{}); | 3405 | return coff.base.comp.link_diags.fail("exports name table limit reached", .{}); |
| ... | @@ -2714,19 +3410,23 @@ fn updateExportsInner( | ... | @@ -2714,19 +3410,23 @@ fn updateExportsInner( |
| 2714 | @memcpy(name_table_slice[name_index..][0 .. name.len + 1], name[0 .. name.len + 1]); | 3410 | @memcpy(name_table_slice[name_index..][0 .. name.len + 1], name[0 .. name.len + 1]); |
| 2715 | | 3411 | |
| 2716 | // If the new name sorts after the current tail of the sorted list, we don't need to re-sort | 3412 | // If the new name sorts after the current tail of the sorted list, we don't need to re-sort |
| 2717 | const ordinal_table_slice = coff.exportOrdinalTableSlice(); | 3413 | { |
| 2718 | if (ordinal_table_slice.len > 0 and !coff.export_table.pending_sort) { | 3414 | const ordinal_table_slice = coff.exportOrdinalTableSlice(); |
| 2719 | const tail_index: ExportTable.Ordinal = | 3415 | if (ordinal_table_slice.len > 0 and !coff.export_table.pending_sort) { |
| 2720 | @enumFromInt(ordinal_table_slice[ordinal_table_slice.len - 1].unbiased_ordinal); | 3416 | const tail_index: ExportTable.Ordinal = |
| 2721 | const tail_entry = tail_index.get(coff); | 3417 | @enumFromInt(ordinal_table_slice[ordinal_table_slice.len - 1].unbiased_ordinal); |
| 2722 | const tail_name = name_table_slice[tail_entry.name_index..][0..tail_entry.name_len]; | 3418 | const tail_entry = tail_index.get(coff); |
| 2723 | coff.export_table.pending_sort = std.mem.lessThan(u8, name, tail_name); | 3419 | const tail_name = name_table_slice[tail_entry.name_index..][0..tail_entry.name_len]; |
| | 3420 | coff.export_table.pending_sort = std.mem.lessThan(u8, name, tail_name); |
| | 3421 | } |
| 2724 | } | 3422 | } |
| 2725 | | 3423 | |
| 2726 | const edt = coff.exportDirectoryTable(); | 3424 | const edt = coff.exportDirectoryTable(); |
| 2727 | coff.targetStore(&edt.number_of_names, @intCast(export_count)); | 3425 | coff.targetStore(&edt.number_of_names, @intCast(export_count)); |
| 2728 | edt.number_of_entries = edt.number_of_names; | 3426 | edt.number_of_entries = edt.number_of_names; |
| 2729 | | 3427 | |
| | 3428 | // TODO: If we had an estimate of the total number of exports this could be a lot more efficient |
| | 3429 | |
| 2730 | try coff.export_table.export_address_table_si.node(coff).resize( | 3430 | try coff.export_table.export_address_table_si.node(coff).resize( |
| 2731 | &coff.mf, | 3431 | &coff.mf, |
| 2732 | gpa, | 3432 | gpa, |
| ... | @@ -2783,22 +3483,24 @@ pub fn deleteExport(coff: *Coff, exported: Zcu.Exported, name: InternPool.NullTe | ... | @@ -2783,22 +3483,24 @@ pub fn deleteExport(coff: *Coff, exported: Zcu.Exported, name: InternPool.NullTe |
| 2783 | _ = name; | 3483 | _ = name; |
| 2784 | } | 3484 | } |
| 2785 | | 3485 | |
| 2786 | pub fn dump(coff: *Coff, tid: Zcu.PerThread.Id) Io.Cancelable!void { | 3486 | fn dumpStderr(coff: *Coff, tid: Zcu.PerThread.Id) !void { |
| 2787 | const comp = coff.base.comp; | 3487 | const comp = coff.base.comp; |
| 2788 | const io = comp.io; | 3488 | const io = comp.io; |
| 2789 | var buffer: [512]u8 = undefined; | 3489 | var buffer: [512]u8 = undefined; |
| 2790 | const stderr = try io.lockStderr(&buffer, null); | 3490 | const stderr = try io.lockStderr(&buffer, null); |
| 2791 | defer io.unlockStderr(); | 3491 | defer io.unlockStderr(); |
| 2792 | const w = &stderr.file_writer.interface; | 3492 | const w = &stderr.file_writer.interface; |
| 2793 | coff.printNode(tid, w, .root, 0) catch |err| switch (err) { | 3493 | try coff.dump(w, tid); |
| 2794 | error.WriteFailed => return stderr.err.?, | 3494 | } |
| 2795 | }; | 3495 | |
| | 3496 | pub fn dump(coff: *Coff, w: *Io.Writer, tid: Zcu.PerThread.Id) !void { |
| | 3497 | try coff.printNode(tid, w, .root, 0); |
| 2796 | } | 3498 | } |
| 2797 | | 3499 | |
| 2798 | pub fn printNode( | 3500 | pub fn printNode( |
| 2799 | coff: *Coff, | 3501 | coff: *Coff, |
| 2800 | tid: Zcu.PerThread.Id, | 3502 | tid: Zcu.PerThread.Id, |
| 2801 | w: *std.Io.Writer, | 3503 | w: *Io.Writer, |
| 2802 | ni: MappedFile.Node.Index, | 3504 | ni: MappedFile.Node.Index, |
| 2803 | indent: usize, | 3505 | indent: usize, |
| 2804 | ) !void { | 3506 | ) !void { |
| ... | @@ -2830,7 +3532,7 @@ pub fn printNode( | ... | @@ -2830,7 +3532,7 @@ pub fn printNode( |
| 2830 | const ip = &zcu.intern_pool; | 3532 | const ip = &zcu.intern_pool; |
| 2831 | const nav = ip.getNav(nmi.navIndex(coff)); | 3533 | const nav = ip.getNav(nmi.navIndex(coff)); |
| 2832 | try w.print("({f}, {f})", .{ | 3534 | try w.print("({f}, {f})", .{ |
| 2833 | Type.fromInterned(nav.typeOf(ip)).fmt(.{ .zcu = zcu, .tid = tid }), | 3535 | Type.fromInterned(ip.typeOf(nav.resolved.?.value)).fmt(.{ .zcu = zcu, .tid = tid }), |
| 2834 | nav.fqn.fmt(ip), | 3536 | nav.fqn.fmt(ip), |
| 2835 | }); | 3537 | }); |
| 2836 | }, | 3538 | }, |
| ... | @@ -2876,7 +3578,7 @@ pub fn printNode( | ... | @@ -2876,7 +3578,7 @@ pub fn printNode( |
| 2876 | const line_len = 0x10; | 3578 | const line_len = 0x10; |
| 2877 | var line_it = std.mem.window( | 3579 | var line_it = std.mem.window( |
| 2878 | u8, | 3580 | u8, |
| 2879 | coff.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)], | 3581 | coff.mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)], |
| 2880 | line_len, | 3582 | line_len, |
| 2881 | line_len, | 3583 | line_len, |
| 2882 | ); | 3584 | ); |