| ... | ... | @@ -23,6 +23,11 @@ const implib = @import("../libs/mingw/implib.zig"); |
| 23 | 23 | base: link.File, |
| 24 | 24 | mf: MappedFile, |
| 25 | 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 | 31 | import_table: ImportTable, |
| 27 | 32 | export_table: ExportTable, |
| 28 | 33 | strings: std.HashMapUnmanaged( |
| ... | ... | @@ -137,18 +142,27 @@ pub const msdos_stub: [120]u8 = .{ |
| 137 | 142 | pub const Node = union(enum) { |
| 138 | 143 | file, |
| 139 | 144 | header, |
| 145 | /// Images and archives only. |
| 140 | 146 | signature, |
| 147 | /// Archives only. |
| 148 | archive_member_header: Member.Index, |
| 149 | archive_member: Member.Index, |
| 150 | |
| 141 | 151 | coff_header, |
| 152 | /// Image only |
| 142 | 153 | optional_header, |
| 154 | /// Image only |
| 143 | 155 | data_directories, |
| 144 | 156 | section_table, |
| 145 | 157 | image_section: Symbol.Index, |
| 146 | 158 | |
| 159 | /// Only images contain imports |
| 147 | 160 | import_directory_table, |
| 148 | 161 | import_lookup_table: ImportTable.Index, |
| 149 | 162 | import_address_table: ImportTable.Index, |
| 150 | 163 | import_hint_name_table: ImportTable.Index, |
| 151 | 164 | |
| 165 | /// Only images contain exports |
| 152 | 166 | export_directory_table, |
| 153 | 167 | export_address_table, |
| 154 | 168 | export_name_pointer_table, |
| ... | ... | @@ -163,6 +177,9 @@ pub const Node = union(enum) { |
| 163 | 177 | lazy_code: LazyMapRef.Index(.code), |
| 164 | 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 | 183 | pub const PseudoSectionMapIndex = enum(u32) { |
| 167 | 184 | _, |
| 168 | 185 | |
| ... | ... | @@ -262,6 +279,14 @@ pub const Node = union(enum) { |
| 262 | 279 | file, |
| 263 | 280 | header, |
| 264 | 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 | 290 | coff_header, |
| 266 | 291 | optional_header, |
| 267 | 292 | data_directories, |
| ... | ... | @@ -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 | 439 | pub const ExportTable = struct { |
| 283 | 440 | ni: MappedFile.Node.Index, |
| 441 | export_directory_table_ni: MappedFile.Node.Index, |
| 284 | 442 | export_address_table_si: Symbol.Index, |
| 285 | 443 | name_pointer_table_ni: MappedFile.Node.Index, |
| 286 | 444 | ordinal_table_ni: MappedFile.Node.Index, |
| ... | ... | @@ -535,6 +693,13 @@ pub const Reloc = extern struct { |
| 535 | 693 | const loc_slice = loc_sym.ni.slice(&coff.mf)[@intCast(reloc.offset)..]; |
| 536 | 694 | const target_rva = target_sym.rva +% @as(u64, @bitCast(reloc.addend)); |
| 537 | 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 | 703 | switch (coff.targetLoad(&coff.headerPtr().machine)) { |
| 539 | 704 | else => |machine| @panic(@tagName(machine)), |
| 540 | 705 | .AMD64 => switch (reloc.type.AMD64) { |
| ... | ... | @@ -543,13 +708,13 @@ pub const Reloc = extern struct { |
| 543 | 708 | .ADDR64 => std.mem.writeInt( |
| 544 | 709 | u64, |
| 545 | 710 | loc_slice[0..8], |
| 546 | | coff.optionalHeaderField(.image_base) + target_rva, |
| 711 | base + target_rva, |
| 547 | 712 | target_endian, |
| 548 | 713 | ), |
| 549 | 714 | .ADDR32 => std.mem.writeInt( |
| 550 | 715 | u32, |
| 551 | 716 | loc_slice[0..4], |
| 552 | | @intCast(coff.optionalHeaderField(.image_base) + target_rva), |
| 717 | @intCast(base + target_rva), |
| 553 | 718 | target_endian, |
| 554 | 719 | ), |
| 555 | 720 | .ADDR32NB => std.mem.writeInt( |
| ... | ... | @@ -607,7 +772,7 @@ pub const Reloc = extern struct { |
| 607 | 772 | .DIR16 => std.mem.writeInt( |
| 608 | 773 | u16, |
| 609 | 774 | loc_slice[0..2], |
| 610 | | @intCast(coff.optionalHeaderField(.image_base) + target_rva), |
| 775 | @intCast(base + target_rva), |
| 611 | 776 | target_endian, |
| 612 | 777 | ), |
| 613 | 778 | .REL16 => std.mem.writeInt( |
| ... | ... | @@ -619,7 +784,7 @@ pub const Reloc = extern struct { |
| 619 | 784 | .DIR32 => std.mem.writeInt( |
| 620 | 785 | u32, |
| 621 | 786 | loc_slice[0..4], |
| 622 | | @intCast(coff.optionalHeaderField(.image_base) + target_rva), |
| 787 | @intCast(base + target_rva), |
| 623 | 788 | target_endian, |
| 624 | 789 | ), |
| 625 | 790 | .DIR32NB => std.mem.writeInt( |
| ... | ... | @@ -691,14 +856,6 @@ fn create( |
| 691 | 856 | assert(target.ofmt == .coff); |
| 692 | 857 | if (target.cpu.arch.endian() != comptime targetEndian(undefined)) |
| 693 | 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 | 859 | const machine = target.toCoffMachine(); |
| 703 | 860 | const timestamp: u32 = 0; |
| 704 | 861 | const major_subsystem_version = options.major_subsystem_version orelse 6; |
| ... | ... | @@ -743,12 +900,20 @@ fn create( |
| 743 | 900 | }, |
| 744 | 901 | .mf = try .init(file, comp.gpa, io), |
| 745 | 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 | 910 | .import_table = .{ |
| 747 | 911 | .ni = .none, |
| 748 | 912 | .entries = .empty, |
| 749 | 913 | }, |
| 750 | 914 | .export_table = .{ |
| 751 | 915 | .ni = .none, |
| 916 | .export_directory_table_ni = .none, |
| 752 | 917 | .export_address_table_si = .null, |
| 753 | 918 | .name_pointer_table_ni = .none, |
| 754 | 919 | .ordinal_table_ni = .none, |
| ... | ... | @@ -785,7 +950,6 @@ fn create( |
| 785 | 950 | } |
| 786 | 951 | |
| 787 | 952 | try coff.initHeaders( |
| 788 | | is_image, |
| 789 | 953 | machine, |
| 790 | 954 | timestamp, |
| 791 | 955 | major_subsystem_version, |
| ... | ... | @@ -801,6 +965,7 @@ pub fn deinit(coff: *Coff) void { |
| 801 | 965 | const gpa = coff.base.comp.gpa; |
| 802 | 966 | coff.mf.deinit(gpa); |
| 803 | 967 | coff.nodes.deinit(gpa); |
| 968 | coff.long_names_table.entries.deinit(gpa); |
| 804 | 969 | coff.import_table.entries.deinit(gpa); |
| 805 | 970 | coff.export_table.entries.deinit(gpa); |
| 806 | 971 | coff.strings.deinit(gpa); |
| ... | ... | @@ -818,9 +983,32 @@ pub fn deinit(coff: *Coff) void { |
| 818 | 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 | 1010 | fn initHeaders( |
| 822 | 1011 | coff: *Coff, |
| 823 | | is_image: bool, |
| 824 | 1012 | machine: std.coff.IMAGE.FILE.MACHINE, |
| 825 | 1013 | timestamp: u32, |
| 826 | 1014 | major_subsystem_version: u16, |
| ... | ... | @@ -833,6 +1021,8 @@ fn initHeaders( |
| 833 | 1021 | const gpa = comp.gpa; |
| 834 | 1022 | const target_endian = coff.targetEndian(); |
| 835 | 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 | 1027 | const optional_header_size: u16 = if (is_image) switch (magic) { |
| 838 | 1028 | _ => unreachable, |
| ... | ... | @@ -843,33 +1033,106 @@ fn initHeaders( |
| 843 | 1033 | else |
| 844 | 1034 | 0; |
| 845 | 1035 | |
| 846 | | const expected_nodes_len = Node.known_count + 12 + |
| 847 | | @as(usize, @intFromBool(comp.config.any_non_single_threaded)) * 2; |
| 1036 | var expected_nodes_len: usize = Node.known_count; |
| 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 | 1044 | try coff.nodes.ensureTotalCapacity(gpa, expected_nodes_len); |
| 849 | 1045 | coff.nodes.appendAssumeCapacity(.file); |
| 850 | 1046 | |
| 851 | 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 | 1049 | .alignment = coff.mf.flags.block_size, |
| 854 | 1050 | .fixed = true, |
| 855 | 1051 | })); |
| 856 | 1052 | coff.nodes.appendAssumeCapacity(.header); |
| 857 | 1053 | |
| 1054 | const pe_signature = "PE\x00\x00"; |
| 1055 | const archive_signature = "!<arch>\n"; |
| 1056 | |
| 858 | 1057 | const signature_ni = Node.known.signature; |
| 859 | | assert(signature_ni == try coff.mf.addOnlyChildNode(gpa, header_ni, .{ |
| 860 | | .size = (if (is_image) msdos_stub.len else 0) + "PE\x00\x00".len, |
| 1058 | assert(signature_ni == try coff.mf.addLastChildNode(gpa, if (is_image) header_ni else Node.known.file, .{ |
| 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 | 1065 | .alignment = .@"4", |
| 862 | 1066 | .fixed = true, |
| 863 | 1067 | })); |
| 864 | 1068 | coff.nodes.appendAssumeCapacity(.signature); |
| 865 | | { |
| 866 | | const signature_slice = signature_ni.slice(&coff.mf); |
| 867 | | if (is_image) @memcpy(signature_slice[0..msdos_stub.len], &msdos_stub); |
| 868 | | @memcpy(signature_slice[signature_slice.len - 4 ..], "PE\x00\x00"); |
| 1069 | |
| 1070 | const signature_slice = signature_ni.slice(&coff.mf); |
| 1071 | if (is_image) { |
| 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 | 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 | 1136 | .size = @sizeOf(std.coff.Header), |
| 874 | 1137 | .alignment = .@"4", |
| 875 | 1138 | .fixed = true, |
| ... | ... | @@ -897,7 +1160,7 @@ fn initHeaders( |
| 897 | 1160 | } |
| 898 | 1161 | |
| 899 | 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 | 1164 | .size = optional_header_size, |
| 902 | 1165 | .alignment = .@"4", |
| 903 | 1166 | .fixed = true, |
| ... | ... | @@ -1009,13 +1272,13 @@ fn initHeaders( |
| 1009 | 1272 | } |
| 1010 | 1273 | |
| 1011 | 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 | 1276 | .size = data_directories_size, |
| 1014 | 1277 | .alignment = .@"4", |
| 1015 | 1278 | .fixed = true, |
| 1016 | 1279 | })); |
| 1017 | 1280 | coff.nodes.appendAssumeCapacity(.data_directories); |
| 1018 | | { |
| 1281 | if (is_image) { |
| 1019 | 1282 | const data_directories = coff.dataDirectorySlice(); |
| 1020 | 1283 | @memset(data_directories, .{ .virtual_address = 0, .size = 0 }); |
| 1021 | 1284 | if (target_endian != native_endian) std.mem.byteSwapAllFields( |
| ... | ... | @@ -1025,7 +1288,7 @@ fn initHeaders( |
| 1025 | 1288 | } |
| 1026 | 1289 | |
| 1027 | 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 | 1292 | .alignment = .@"4", |
| 1030 | 1293 | .fixed = true, |
| 1031 | 1294 | })); |
| ... | ... | @@ -1057,43 +1320,45 @@ fn initHeaders( |
| 1057 | 1320 | .MEM_READ = true, |
| 1058 | 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 | 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 | 1336 | .@".edata", |
| 1074 | 1337 | .of(std.coff.ExportDirectoryTable), |
| 1075 | 1338 | .{ .read = true }, |
| 1076 | 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 | 1342 | gpa, |
| 1080 | | edata_section_ni, |
| 1343 | coff.export_table.ni, |
| 1081 | 1344 | .{ |
| 1082 | 1345 | .size = @sizeOf(std.coff.ExportDirectoryTable) + file_name.len + 1, |
| 1083 | | .alignment = .of(std.coff.ExportDirectoryTable), |
| 1084 | | .fixed = true, |
| 1085 | 1346 | .moved = true, |
| 1347 | .fixed = true, |
| 1086 | 1348 | }, |
| 1087 | 1349 | ); |
| 1350 | coff.nodes.appendAssumeCapacity(.export_directory_table); |
| 1088 | 1351 | |
| 1089 | 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]); |
| 1091 | | @memset(coff.export_table.ni.slice(&coff.mf)[name_index + file_name.len ..], 0); |
| 1353 | const table_slice = coff.export_table.export_directory_table_ni.slice(&coff.mf); |
| 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, .{ |
| 1094 | | .alignment = .of(u32), |
| 1357 | const export_address_table_ni = try coff.mf.addLastChildNode(gpa, coff.export_table.ni, .{ |
| 1358 | .alignment = .of(std.coff.ExportAddressTableEntry), |
| 1095 | 1359 | .moved = true, |
| 1096 | 1360 | }); |
| 1361 | coff.nodes.appendAssumeCapacity(.export_address_table); |
| 1097 | 1362 | |
| 1098 | 1363 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); |
| 1099 | 1364 | coff.export_table.export_address_table_si = coff.addSymbolAssumeCapacity(); |
| ... | ... | @@ -1103,25 +1368,24 @@ fn initHeaders( |
| 1103 | 1368 | assert(export_address_table_sym.loc_relocs == .none); |
| 1104 | 1369 | export_address_table_sym.loc_relocs = @enumFromInt(coff.relocs.items.len); |
| 1105 | 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, .{ |
| 1109 | | .alignment = .of(u32), |
| 1373 | coff.export_table.name_pointer_table_ni = try coff.mf.addLastChildNode(gpa, coff.export_table.ni, .{ |
| 1374 | .alignment = .of(std.coff.ExportNamePointerTableEntry), |
| 1110 | 1375 | .moved = true, |
| 1111 | 1376 | }); |
| 1112 | | coff.export_table.ordinal_table_ni = try coff.mf.addLastChildNode(gpa, edata_section_ni, .{ |
| 1113 | | .alignment = .of(u16), |
| 1377 | coff.nodes.appendAssumeCapacity(.export_name_pointer_table); |
| 1378 | |
| 1379 | coff.export_table.ordinal_table_ni = try coff.mf.addLastChildNode(gpa, coff.export_table.ni, .{ |
| 1380 | .alignment = .of(std.coff.ExportOrdinalTableEntry), |
| 1114 | 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 | 1386 | .alignment = .of(u8), |
| 1118 | 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 | 1389 | coff.nodes.appendAssumeCapacity(.export_name_table); |
| 1126 | 1390 | |
| 1127 | 1391 | const export_directory_table = coff.exportDirectoryTable(); |
| ... | ... | @@ -1145,11 +1409,9 @@ fn initHeaders( |
| 1145 | 1409 | // While tls variables allocated at runtime are writable, the template itself is not |
| 1146 | 1410 | if (comp.config.any_non_single_threaded) _ = try coff.objectSectionMapIndex( |
| 1147 | 1411 | .@".tls$", |
| 1148 | | coff.mf.flags.block_size, |
| 1412 | if (is_image) coff.mf.flags.block_size else .@"1", |
| 1149 | 1413 | .{ .read = true }, |
| 1150 | 1414 | ); |
| 1151 | | |
| 1152 | | assert(coff.nodes.len == expected_nodes_len); |
| 1153 | 1415 | } |
| 1154 | 1416 | |
| 1155 | 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 | 1443 | .file, |
| 1182 | 1444 | .header, |
| 1183 | 1445 | .signature, |
| 1446 | .archive_member_header, |
| 1447 | .archive_member, |
| 1184 | 1448 | .coff_header, |
| 1185 | 1449 | .optional_header, |
| 1186 | 1450 | .data_directories, |
| 1187 | 1451 | .section_table, |
| 1188 | 1452 | .export_name_table, |
| 1453 | .placeholder, |
| 1189 | 1454 | => unreachable, |
| 1190 | 1455 | .image_section => |si| si, |
| 1191 | 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 | 1537 | } |
| 1273 | 1538 | |
| 1274 | 1539 | pub fn headerPtr(coff: *Coff) *std.coff.Header { |
| 1540 | assert(coff.base.comp.zcu != null); |
| 1275 | 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 | 1589 | pub fn optionalHeaderStandardPtr(coff: *Coff) *std.coff.OptionalHeader { |
| 1279 | 1590 | return @ptrCast(@alignCast( |
| 1280 | 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 | 1597 | @"PE32+": *std.coff.OptionalHeader.@"PE32+", |
| 1287 | 1598 | }; |
| 1288 | 1599 | pub fn optionalHeaderPtr(coff: *Coff) OptionalHeaderPtr { |
| 1600 | assert(coff.isImage()); |
| 1289 | 1601 | const slice = Node.known.optional_header.slice(&coff.mf); |
| 1290 | 1602 | return switch (coff.targetLoad(&coff.optionalHeaderStandardPtr().magic)) { |
| 1291 | 1603 | _ => unreachable, |
| ... | ... | @@ -1300,6 +1612,7 @@ pub fn optionalHeaderField( |
| 1300 | 1612 | coff: *Coff, |
| 1301 | 1613 | comptime field: std.meta.FieldEnum(std.coff.OptionalHeader.@"PE32+"), |
| 1302 | 1614 | ) @FieldType(std.coff.OptionalHeader.@"PE32+", @tagName(field)) { |
| 1615 | assert(coff.isImage()); |
| 1303 | 1616 | return switch (coff.optionalHeaderPtr()) { |
| 1304 | 1617 | inline else => |optional_header| coff.targetLoad(&@field(optional_header, @tagName(field))), |
| 1305 | 1618 | }; |
| ... | ... | @@ -1308,6 +1621,7 @@ pub fn optionalHeaderField( |
| 1308 | 1621 | pub fn dataDirectorySlice( |
| 1309 | 1622 | coff: *Coff, |
| 1310 | 1623 | ) *[std.coff.IMAGE.DIRECTORY_ENTRY.len]std.coff.ImageDataDirectory { |
| 1624 | assert(coff.isImage()); |
| 1311 | 1625 | return @ptrCast(@alignCast(Node.known.data_directories.slice(&coff.mf))); |
| 1312 | 1626 | } |
| 1313 | 1627 | pub fn dataDirectoryPtr( |
| ... | ... | @@ -1322,6 +1636,7 @@ pub fn sectionTableSlice(coff: *Coff) []std.coff.SectionHeader { |
| 1322 | 1636 | } |
| 1323 | 1637 | |
| 1324 | 1638 | pub fn importDirectoryTableSlice(coff: *Coff) []std.coff.ImportDirectoryEntry { |
| 1639 | assert(coff.isImage()); |
| 1325 | 1640 | return @ptrCast(@alignCast(coff.import_table.ni.slice(&coff.mf))); |
| 1326 | 1641 | } |
| 1327 | 1642 | pub fn importDirectoryEntryPtr( |
| ... | ... | @@ -1332,10 +1647,13 @@ pub fn importDirectoryEntryPtr( |
| 1332 | 1647 | } |
| 1333 | 1648 | |
| 1334 | 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 | 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 | 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 | 1706 | } |
| 1389 | 1707 | |
| 1390 | 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 | 1717 | const gpa = coff.base.comp.gpa; |
| 1392 | 1718 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); |
| 1393 | 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 | 1724 | sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity(); |
| 1399 | 1725 | coff.synth_prog_node.increaseEstimatedTotalItems(1); |
| 1400 | 1726 | } |
| 1401 | | return sym_gop.value_ptr.*; |
| 1727 | return sym_gop; |
| 1402 | 1728 | } |
| 1403 | 1729 | |
| 1404 | 1730 | fn navSection( |
| ... | ... | @@ -1500,10 +1826,187 @@ pub fn getVAddr(coff: *Coff, reloc_info: link.File.RelocInfo, target_si: Symbol. |
| 1500 | 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 | 2007 | fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags) !Symbol.Index { |
| 2008 | assert(coff.base.comp.zcu != null); |
| 2009 | |
| 1507 | 2010 | const gpa = coff.base.comp.gpa; |
| 1508 | 2011 | try coff.nodes.ensureUnusedCapacity(gpa, 1); |
| 1509 | 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 | 2021 | gpa, |
| 1519 | 2022 | @sizeOf(std.coff.SectionHeader) * section_table_len, |
| 1520 | 2023 | ); |
| 1521 | | const ni = try coff.mf.addLastChildNode(gpa, .root, .{ |
| 1522 | | .alignment = coff.mf.flags.block_size, |
| 2024 | |
| 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 | 2032 | .moved = true, |
| 1524 | 2033 | .bubbles_moved = false, |
| 1525 | 2034 | }); |
| 2035 | |
| 1526 | 2036 | const si = coff.addSymbolAssumeCapacity(); |
| 1527 | 2037 | coff.image_section_table.appendAssumeCapacity(si); |
| 1528 | 2038 | coff.nodes.appendAssumeCapacity(.{ .image_section = si }); |
| 1529 | 2039 | const section_table = coff.sectionTableSlice(); |
| 1530 | | const virtual_size = coff.optionalHeaderField(.section_alignment); |
| 1531 | | const rva: u32 = switch (section_index) { |
| 1532 | | 0 => @intCast(Node.known.header.location(&coff.mf).resolve(&coff.mf)[1]), |
| 1533 | | else => coff.image_section_table.items[section_index - 1].get(coff).rva + |
| 1534 | | coff.targetLoad(&section_table[section_index - 1].virtual_size), |
| 1535 | | }; |
| 2040 | |
| 2041 | const virtual_size, const rva = if (coff.isImage()) block: { |
| 2042 | const virtual_size = coff.optionalHeaderField(.section_alignment); |
| 2043 | const rva: u32 = switch (section_index) { |
| 2044 | 0 => @intCast(Node.known.header.location(&coff.mf).resolve(&coff.mf)[1]), |
| 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 | 2053 | const sym = si.get(coff); |
| 1538 | 2054 | sym.ni = ni; |
| ... | ... | @@ -1556,12 +2072,16 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags |
| 1556 | 2072 | @memset(section.name[name.len..], 0); |
| 1557 | 2073 | if (coff.targetEndian() != native_endian) |
| 1558 | 2074 | std.mem.byteSwapAllFields(std.coff.SectionHeader, section); |
| 1559 | | switch (coff.optionalHeaderPtr()) { |
| 1560 | | inline else => |optional_header| coff.targetStore( |
| 1561 | | &optional_header.size_of_image, |
| 1562 | | @intCast(rva + virtual_size), |
| 1563 | | ), |
| 2075 | |
| 2076 | if (coff.isImage()) { |
| 2077 | switch (coff.optionalHeaderPtr()) { |
| 2078 | inline else => |optional_header| coff.targetStore( |
| 2079 | &optional_header.size_of_image, |
| 2080 | @intCast(rva + virtual_size), |
| 2081 | ), |
| 2082 | } |
| 1564 | 2083 | } |
| 2084 | |
| 1565 | 2085 | return si; |
| 1566 | 2086 | } |
| 1567 | 2087 | |
| ... | ... | @@ -1686,6 +2206,16 @@ pub fn addReloc( |
| 1686 | 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 | 2219 | pub fn prelink(coff: *Coff, prog_node: std.Progress.Node) link.Error!void { |
| 1690 | 2220 | _ = coff; |
| 1691 | 2221 | _ = prog_node; |
| ... | ... | @@ -1976,6 +2506,11 @@ pub fn flush( |
| 1976 | 2506 | _ = prog_node; |
| 1977 | 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 | 2514 | const comp = coff.base.comp; |
| 1980 | 2515 | |
| 1981 | 2516 | // Implib generation should instead be done via building a MappedFile progressively |
| ... | ... | @@ -1985,8 +2520,8 @@ pub fn flush( |
| 1985 | 2520 | |
| 1986 | 2521 | // hack for stage2_x86_64 + coff |
| 1987 | 2522 | if (comp.compiler_rt_dyn_lib) |crt_file| { |
| 1988 | | const gpa = comp.gpa; |
| 1989 | 2523 | const io = comp.io; |
| 2524 | const gpa = comp.gpa; |
| 1990 | 2525 | |
| 1991 | 2526 | const compiler_rt_sub_path = try std.fs.path.join(gpa, &.{ |
| 1992 | 2527 | std.fs.path.dirname(coff.base.emit.sub_path) orelse "", |
| ... | ... | @@ -2002,6 +2537,14 @@ pub fn flush( |
| 2002 | 2537 | .{}, |
| 2003 | 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 | 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 | 2623 | break :task; |
| 2081 | 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 | 2631 | if (coff.export_table.pending_sort) { |
| 2632 | // TODO: Prog node |
| 2084 | 2633 | coff.export_table.pending_sort = false; |
| 2085 | 2634 | coff.flushExportsSort(); |
| 2086 | 2635 | break :task; |
| ... | ... | @@ -2090,6 +2639,7 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 2090 | 2639 | if (coff.globals.count() > coff.global_pending_index) return true; |
| 2091 | 2640 | for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; |
| 2092 | 2641 | if (coff.mf.updates.items.len > 0) return true; |
| 2642 | if (coff.pending_members.count() > 0) return true; |
| 2093 | 2643 | if (coff.export_table.pending_sort) return true; |
| 2094 | 2644 | return false; |
| 2095 | 2645 | } |
| ... | ... | @@ -2183,6 +2733,10 @@ fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void { |
| 2183 | 2733 | const gpa = zcu.gpa; |
| 2184 | 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 | 2740 | if (gn.lib_name.toSlice(coff)) |lib_name| { |
| 2187 | 2741 | const name = gn.name.toSlice(coff); |
| 2188 | 2742 | try coff.nodes.ensureUnusedCapacity(gpa, 4); |
| ... | ... | @@ -2394,19 +2948,44 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { |
| 2394 | 2948 | } |
| 2395 | 2949 | |
| 2396 | 2950 | fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 2951 | log.debug("flushMoved({s})", .{@tagName(coff.getNode(ni))}); |
| 2397 | 2952 | switch (coff.getNode(ni)) { |
| 2398 | 2953 | .file, |
| 2399 | 2954 | .header, |
| 2400 | 2955 | .signature, |
| 2956 | => unreachable, |
| 2401 | 2957 | .coff_header, |
| 2402 | 2958 | .optional_header, |
| 2403 | 2959 | .data_directories, |
| 2404 | 2960 | .section_table, |
| 2405 | | => unreachable, |
| 2406 | | .image_section => |si| return coff.targetStore( |
| 2407 | | &si.get(coff).section_number.header(coff).pointer_to_raw_data, |
| 2408 | | @intCast(ni.fileLocation(&coff.mf, false).offset), |
| 2409 | | ), |
| 2961 | .placeholder, |
| 2962 | => if (!coff.isArchive()) unreachable, |
| 2963 | .archive_member_header => |mi| { |
| 2964 | const member = mi.get(coff); |
| 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 | 2989 | .import_directory_table => coff.targetStore( |
| 2411 | 2990 | &coff.dataDirectoryPtr(.IMPORT).virtual_address, |
| 2412 | 2991 | coff.computeNodeRva(ni), |
| ... | ... | @@ -2523,32 +3102,69 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 2523 | 3102 | |
| 2524 | 3103 | fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 2525 | 3104 | _, const size = ni.location(&coff.mf).resolve(&coff.mf); |
| 3105 | log.debug("flushResized({s}, 0x{x})", .{ @tagName(coff.getNode(ni)), size }); |
| 3106 | |
| 2526 | 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 | 3115 | .header => { |
| 2529 | | switch (coff.optionalHeaderPtr()) { |
| 2530 | | inline else => |optional_header| coff.targetStore( |
| 2531 | | &optional_header.size_of_headers, |
| 2532 | | @intCast(size), |
| 2533 | | ), |
| 3116 | if (coff.isImage()) { |
| 3117 | switch (coff.optionalHeaderPtr()) { |
| 3118 | inline else => |optional_header| coff.targetStore( |
| 3119 | &optional_header.size_of_headers, |
| 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 | 3161 | .section_table => {}, |
| 2546 | 3162 | .image_section => |si| { |
| 2547 | 3163 | const sym = si.get(coff); |
| 2548 | 3164 | const section_index = sym.section_number.toIndex(); |
| 2549 | 3165 | const section = &coff.sectionTableSlice()[section_index]; |
| 2550 | 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 | 3168 | const virtual_size = std.mem.alignForward( |
| 2553 | 3169 | u32, |
| 2554 | 3170 | @intCast(size * 4), |
| ... | ... | @@ -2562,16 +3178,87 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 2562 | 3178 | &coff.dataDirectoryPtr(.IMPORT).size, |
| 2563 | 3179 | @intCast(size), |
| 2564 | 3180 | ), |
| 2565 | | .import_lookup_table, .import_address_table, .import_hint_name_table => {}, |
| 2566 | | .export_directory_table => coff.targetStore( |
| 2567 | | &coff.dataDirectoryPtr(.EXPORT).size, |
| 2568 | | @intCast(size), |
| 2569 | | ), |
| 2570 | | .export_address_table, .export_name_pointer_table, .export_ordinal_table, .export_name_table => {}, |
| 3181 | .import_lookup_table, |
| 3182 | .import_address_table, |
| 3183 | .import_hint_name_table, |
| 3184 | => {}, |
| 3185 | .export_directory_table => unreachable, |
| 3186 | .export_address_table, |
| 3187 | .export_name_pointer_table, |
| 3188 | .export_ordinal_table, |
| 3189 | .export_name_table, |
| 3190 | => {}, |
| 2571 | 3191 | inline .pseudo_section, |
| 2572 | 3192 | .object_section, |
| 2573 | | => |smi| smi.symbol(coff).get(coff).size = @intCast(size), |
| 2574 | | .global, .nav, .uav, .lazy_code, .lazy_const_data => {}, |
| 3193 | => |smi, tag| { |
| 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 | 3353 | ))), |
| 2667 | 3354 | }; |
| 2668 | 3355 | while (try coff.idle(pt.tid)) {} |
| 3356 | |
| 2669 | 3357 | const exported_ni = exported_si.node(coff); |
| 2670 | 3358 | const exported_sym = exported_si.get(coff); |
| 2671 | 3359 | for (export_indices) |export_index| { |
| 2672 | 3360 | const @"export" = export_index.ptr(zcu); |
| 2673 | 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 | 3364 | const export_sym = export_si.get(coff); |
| 2676 | 3365 | export_sym.ni = exported_ni; |
| 2677 | 3366 | export_sym.rva = exported_sym.rva; |
| ... | ... | @@ -2687,6 +3376,13 @@ fn updateExportsInner( |
| 2687 | 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 | 3386 | if (coff.export_table.ni == .none) continue; |
| 2691 | 3387 | |
| 2692 | 3388 | const entries_ctx = ExportTable.Adapter{ .coff = coff }; |
| ... | ... | @@ -2703,7 +3399,7 @@ fn updateExportsInner( |
| 2703 | 3399 | if (export_count > std.math.maxInt(@FieldType(std.coff.ExportDirectoryTable, "number_of_entries"))) |
| 2704 | 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 | 3403 | const new_name_table_size = name_index + name.len + 1; |
| 2708 | 3404 | if (new_name_table_size > std.math.maxInt(@FieldType(ExportTable.Entry, "name_index"))) |
| 2709 | 3405 | return coff.base.comp.link_diags.fail("exports name table limit reached", .{}); |
| ... | ... | @@ -2714,19 +3410,23 @@ fn updateExportsInner( |
| 2714 | 3410 | @memcpy(name_table_slice[name_index..][0 .. name.len + 1], name[0 .. name.len + 1]); |
| 2715 | 3411 | |
| 2716 | 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(); |
| 2718 | | if (ordinal_table_slice.len > 0 and !coff.export_table.pending_sort) { |
| 2719 | | const tail_index: ExportTable.Ordinal = |
| 2720 | | @enumFromInt(ordinal_table_slice[ordinal_table_slice.len - 1].unbiased_ordinal); |
| 2721 | | const tail_entry = tail_index.get(coff); |
| 2722 | | const tail_name = name_table_slice[tail_entry.name_index..][0..tail_entry.name_len]; |
| 2723 | | coff.export_table.pending_sort = std.mem.lessThan(u8, name, tail_name); |
| 3413 | { |
| 3414 | const ordinal_table_slice = coff.exportOrdinalTableSlice(); |
| 3415 | if (ordinal_table_slice.len > 0 and !coff.export_table.pending_sort) { |
| 3416 | const tail_index: ExportTable.Ordinal = |
| 3417 | @enumFromInt(ordinal_table_slice[ordinal_table_slice.len - 1].unbiased_ordinal); |
| 3418 | const tail_entry = tail_index.get(coff); |
| 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 | 3424 | const edt = coff.exportDirectoryTable(); |
| 2727 | 3425 | coff.targetStore(&edt.number_of_names, @intCast(export_count)); |
| 2728 | 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 | 3430 | try coff.export_table.export_address_table_si.node(coff).resize( |
| 2731 | 3431 | &coff.mf, |
| 2732 | 3432 | gpa, |
| ... | ... | @@ -2783,22 +3483,24 @@ pub fn deleteExport(coff: *Coff, exported: Zcu.Exported, name: InternPool.NullTe |
| 2783 | 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 | 3487 | const comp = coff.base.comp; |
| 2788 | 3488 | const io = comp.io; |
| 2789 | 3489 | var buffer: [512]u8 = undefined; |
| 2790 | 3490 | const stderr = try io.lockStderr(&buffer, null); |
| 2791 | 3491 | defer io.unlockStderr(); |
| 2792 | 3492 | const w = &stderr.file_writer.interface; |
| 2793 | | coff.printNode(tid, w, .root, 0) catch |err| switch (err) { |
| 2794 | | error.WriteFailed => return stderr.err.?, |
| 2795 | | }; |
| 3493 | try coff.dump(w, tid); |
| 3494 | } |
| 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 | 3500 | pub fn printNode( |
| 2799 | 3501 | coff: *Coff, |
| 2800 | 3502 | tid: Zcu.PerThread.Id, |
| 2801 | | w: *std.Io.Writer, |
| 3503 | w: *Io.Writer, |
| 2802 | 3504 | ni: MappedFile.Node.Index, |
| 2803 | 3505 | indent: usize, |
| 2804 | 3506 | ) !void { |
| ... | ... | @@ -2830,7 +3532,7 @@ pub fn printNode( |
| 2830 | 3532 | const ip = &zcu.intern_pool; |
| 2831 | 3533 | const nav = ip.getNav(nmi.navIndex(coff)); |
| 2832 | 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 | 3536 | nav.fqn.fmt(ip), |
| 2835 | 3537 | }); |
| 2836 | 3538 | }, |
| ... | ... | @@ -2876,7 +3578,7 @@ pub fn printNode( |
| 2876 | 3578 | const line_len = 0x10; |
| 2877 | 3579 | var line_it = std.mem.window( |
| 2878 | 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 | 3582 | line_len, |
| 2881 | 3583 | line_len, |
| 2882 | 3584 | ); |