| ... | @@ -65,8 +65,6 @@ section_merge_pending_index: u32, | ... | @@ -65,8 +65,6 @@ section_merge_pending_index: u32, |
| 65 | symbols: std.ArrayList(Symbol), | 65 | symbols: std.ArrayList(Symbol), |
| 66 | globals: std.array_hash_map.Auto(GlobalName, Symbol.Index), | 66 | globals: std.array_hash_map.Auto(GlobalName, Symbol.Index), |
| 67 | global_pending_index: u32, | 67 | global_pending_index: u32, |
| 68 | late_globals: std.ArrayList(Node.GlobalMapIndex), | | |
| 69 | late_globals_pending_index: u32, | | |
| 70 | navs: std.array_hash_map.Auto(InternPool.Nav.Index, Symbol.Index), | 68 | navs: std.array_hash_map.Auto(InternPool.Nav.Index, Symbol.Index), |
| 71 | uavs: std.array_hash_map.Auto(InternPool.Index, Symbol.Index), | 69 | uavs: std.array_hash_map.Auto(InternPool.Index, Symbol.Index), |
| 72 | lazy: std.EnumArray(link.File.LazySymbol.Kind, struct { | 70 | lazy: std.EnumArray(link.File.LazySymbol.Kind, struct { |
| ... | @@ -188,17 +186,16 @@ pub const Node = union(enum) { | ... | @@ -188,17 +186,16 @@ pub const Node = union(enum) { |
| 188 | archive_member: Member.Index, | 186 | archive_member: Member.Index, |
| 189 | | 187 | |
| 190 | coff_header, | 188 | coff_header, |
| | 189 | |
| 191 | /// Image only | 190 | /// Image only |
| 192 | optional_header, | 191 | optional_header, |
| 193 | /// Image only | | |
| 194 | data_directories, | 192 | data_directories, |
| 195 | | 193 | |
| 196 | section_table, | 194 | section_table, |
| 197 | // Archives and objects only | 195 | |
| | 196 | /// Archives and objects only |
| 198 | symbol_table, | 197 | symbol_table, |
| 199 | // Archives and objects only | | |
| 200 | string_table, | 198 | string_table, |
| 201 | // Archives and objects only | | |
| 202 | relocation_table: Symbol.SectionNumber, | 199 | relocation_table: Symbol.SectionNumber, |
| 203 | relocation_table_entry: Reloc.Index, | 200 | relocation_table_entry: Reloc.Index, |
| 204 | | 201 | |
| ... | @@ -220,11 +217,12 @@ pub const Node = union(enum) { | ... | @@ -220,11 +217,12 @@ pub const Node = union(enum) { |
| 220 | pseudo_section: PseudoSectionMapIndex, | 217 | pseudo_section: PseudoSectionMapIndex, |
| 221 | object_section: ObjectSectionMapIndex, | 218 | object_section: ObjectSectionMapIndex, |
| 222 | input_section: InputSection.Index, | 219 | input_section: InputSection.Index, |
| 223 | import_thunk: GlobalMapIndex, // TODO: Rename to import_thunk | 220 | import_thunk: GlobalMapIndex, |
| 224 | nav: NavMapIndex, | 221 | nav: NavMapIndex, |
| 225 | uav: UavMapIndex, | 222 | uav: UavMapIndex, |
| 226 | lazy_code: LazyMapRef.Index(.code), | 223 | lazy_code: LazyMapRef.Index(.code), |
| 227 | lazy_const_data: LazyMapRef.Index(.const_data), | 224 | lazy_const_data: LazyMapRef.Index(.const_data), |
| | 225 | builtin: Symbol.Index, |
| 228 | | 226 | |
| 229 | /// Takes the place of a known node index when that node is not present in the output | 227 | /// Takes the place of a known node index when that node is not present in the output |
| 230 | placeholder, | 228 | placeholder, |
| ... | @@ -945,7 +943,7 @@ pub const Symbol = struct { | ... | @@ -945,7 +943,7 @@ pub const Symbol = struct { |
| 945 | // The size of the symbol | 943 | // The size of the symbol |
| 946 | size: u32, | 944 | size: u32, |
| 947 | /// Only valid when .ni == .input_section and .value_tag == .node_offset | 945 | /// Only valid when .ni == .input_section and .value_tag == .node_offset |
| 948 | /// TODO: This is only used for name lookups, could just be String? | 946 | /// TODO: This is only used for name lookups, could just be String, remove `input_symbols`? |
| 949 | isli: Node.InputSection.LocalIndex, | 947 | isli: Node.InputSection.LocalIndex, |
| 950 | /// The next symbol in the list of aliases of this symbol. | 948 | /// The next symbol in the list of aliases of this symbol. |
| 951 | next_alias_si: Symbol.Index, | 949 | next_alias_si: Symbol.Index, |
| ... | @@ -1322,7 +1320,8 @@ pub const Reloc = extern struct { | ... | @@ -1322,7 +1320,8 @@ pub const Reloc = extern struct { |
| 1322 | switch (target_machine) { | 1320 | switch (target_machine) { |
| 1323 | else => |machine| @panic(@tagName(machine)), | 1321 | else => |machine| @panic(@tagName(machine)), |
| 1324 | .AMD64 => switch (reloc.type.AMD64) { | 1322 | .AMD64 => switch (reloc.type.AMD64) { |
| 1325 | // TODO: Report these later, in reportUndefs -> reportRelocErrs ? | 1323 | // TODO: Could wait to report these later, in reportUndefs -> reportRelocErrs, |
| | 1324 | // so that this function doesn't return an err |
| 1326 | else => |kind| return coff.base.comp.link_diags.fail( | 1325 | else => |kind| return coff.base.comp.link_diags.fail( |
| 1327 | "absolute symbol '{s}' targeted by invalid relocation type: {t}", | 1326 | "absolute symbol '{s}' targeted by invalid relocation type: {t}", |
| 1328 | .{ target_sym.gmi.globalName(coff).name.toSlice(coff), kind }, | 1327 | .{ target_sym.gmi.globalName(coff).name.toSlice(coff), kind }, |
| ... | @@ -1475,8 +1474,10 @@ pub const Reloc = extern struct { | ... | @@ -1475,8 +1474,10 @@ pub const Reloc = extern struct { |
| 1475 | pub fn delete(reloc: *Reloc, coff: *Coff) void { | 1474 | pub fn delete(reloc: *Reloc, coff: *Coff) void { |
| 1476 | if (reloc.sri != .none) { | 1475 | if (reloc.sri != .none) { |
| 1477 | // TODO: Need to remove this from the COFF relocation table (maybe removeswap?) | 1476 | // TODO: Need to remove this from the COFF relocation table (maybe removeswap?) |
| 1478 | // TODO: If this was the last reloc causing something to be in the symbol table, we should remove the sti | 1477 | // TODO: If this was the last reloc causing something to be in the symbol table, we should remove |
| 1479 | // That will require flushSymbolTableIndex on the swapped symbol if we exchange indices | 1478 | // the symbol table entry (and unset sti). That will require flushSymbolTableIndex on the |
| | 1479 | // swapped symbol if we exchange indices |
| | 1480 | unreachable; |
| 1480 | } | 1481 | } |
| 1481 | | 1482 | |
| 1482 | switch (reloc.prev) { | 1483 | switch (reloc.prev) { |
| ... | @@ -1623,8 +1624,6 @@ fn create( | ... | @@ -1623,8 +1624,6 @@ fn create( |
| 1623 | .symbols = .empty, | 1624 | .symbols = .empty, |
| 1624 | .globals = .empty, | 1625 | .globals = .empty, |
| 1625 | .global_pending_index = 0, | 1626 | .global_pending_index = 0, |
| 1626 | .late_globals = .empty, | | |
| 1627 | .late_globals_pending_index = 0, | | |
| 1628 | .navs = .empty, | 1627 | .navs = .empty, |
| 1629 | .uavs = .empty, | 1628 | .uavs = .empty, |
| 1630 | .lazy = .initFill(.{ | 1629 | .lazy = .initFill(.{ |
| ... | @@ -1698,7 +1697,6 @@ pub fn deinit(coff: *Coff) void { | ... | @@ -1698,7 +1697,6 @@ pub fn deinit(coff: *Coff) void { |
| 1698 | coff.object_section_table.deinit(gpa); | 1697 | coff.object_section_table.deinit(gpa); |
| 1699 | coff.symbols.deinit(gpa); | 1698 | coff.symbols.deinit(gpa); |
| 1700 | coff.globals.deinit(gpa); | 1699 | coff.globals.deinit(gpa); |
| 1701 | coff.late_globals.deinit(gpa); | | |
| 1702 | coff.navs.deinit(gpa); | 1700 | coff.navs.deinit(gpa); |
| 1703 | coff.uavs.deinit(gpa); | 1701 | coff.uavs.deinit(gpa); |
| 1704 | for (&coff.lazy.values) |*lazy| lazy.map.deinit(gpa); | 1702 | for (&coff.lazy.values) |*lazy| lazy.map.deinit(gpa); |
| ... | @@ -2109,7 +2107,7 @@ fn initHeaders( | ... | @@ -2109,7 +2107,7 @@ fn initHeaders( |
| 2109 | }); | 2107 | }); |
| 2110 | } | 2108 | } |
| 2111 | | 2109 | |
| 2112 | // TODO: Lazily initialize this instead? | 2110 | // TODO: Lazily initialize this instead, avoid the extra logic for this in flushMoved / flushResized |
| 2113 | coff.import_table.ni = try coff.mf.addLastChildNode( | 2111 | coff.import_table.ni = try coff.mf.addLastChildNode( |
| 2114 | gpa, | 2112 | gpa, |
| 2115 | (try coff.objectSectionMapIndex( | 2113 | (try coff.objectSectionMapIndex( |
| ... | @@ -2225,18 +2223,27 @@ pub fn initBuiltins(coff: *Coff) !void { | ... | @@ -2225,18 +2223,27 @@ pub fn initBuiltins(coff: *Coff) !void { |
| 2225 | sym.ni = Node.known.header; | 2223 | sym.ni = Node.known.header; |
| 2226 | } | 2224 | } |
| 2227 | | 2225 | |
| | 2226 | defer coff.flushSectionMerges() catch unreachable; |
| 2228 | if (coff.isImage() and target.isMinGW() and comp.config.link_libc) { | 2227 | if (coff.isImage() and target.isMinGW() and comp.config.link_libc) { |
| 2229 | try coff.symbols.ensureUnusedCapacity(gpa, 6); | 2228 | try coff.symbols.ensureUnusedCapacity(gpa, 8); |
| 2230 | try coff.globals.ensureUnusedCapacity(gpa, 2); | 2229 | try coff.globals.ensureUnusedCapacity(gpa, 2); |
| 2231 | try coff.nodes.ensureUnusedCapacity(gpa, 6); | 2230 | try coff.nodes.ensureUnusedCapacity(gpa, 8); |
| | 2231 | try coff.section_merges.ensureUnusedCapacity(gpa, 2); |
| 2232 | | 2232 | |
| 2233 | const lists: []const struct { global: []const u8, start: String, end: String } = &.{ | 2233 | const lists: []const struct { global: []const u8, start: String, end: String } = &.{ |
| 2234 | .{ .global = "__CTOR_LIST__", .start = .@".ctors", .end = .@".ctors$ZZZ" }, | 2234 | .{ .global = "__CTOR_LIST__", .start = .@".ctors", .end = .@".ctors$ZZZ" }, |
| 2235 | .{ .global = "__DTOR_LIST__", .start = .@".dtors", .end = .@".dtors$ZZZ" }, | 2235 | .{ .global = "__DTOR_LIST__", .start = .@".dtors", .end = .@".dtors$ZZZ" }, |
| 2236 | }; | 2236 | }; |
| 2237 | | 2237 | |
| | 2238 | // We need to explicitly merge these into .rdata as in objects they can be marked |
| | 2239 | // as MEM_WRITE, and would have mismatced section flags. |
| | 2240 | try coff.section_merges.put(gpa, .@".ctors", .@".rdata"); |
| | 2241 | try coff.section_merges.put(gpa, .@".dtors", .@".rdata"); |
| | 2242 | |
| 2238 | for (lists) |list| { | 2243 | for (lists) |list| { |
| 2239 | const addr_info = coff.targetAddrInfo(); | 2244 | const addr_info = coff.targetAddrInfo(); |
| | 2245 | |
| | 2246 | // Any .(c|d)tor$(.*) input sections will merge in between these sections |
| 2240 | const start_osmi = try coff.objectSectionMapIndex( | 2247 | const start_osmi = try coff.objectSectionMapIndex( |
| 2241 | list.start, | 2248 | list.start, |
| 2242 | addr_info.alignment, | 2249 | addr_info.alignment, |
| ... | @@ -2248,32 +2255,46 @@ pub fn initBuiltins(coff: *Coff) !void { | ... | @@ -2248,32 +2255,46 @@ pub fn initBuiltins(coff: *Coff) !void { |
| 2248 | .{ .read = true, .initialized = true }, | 2255 | .{ .read = true, .initialized = true }, |
| 2249 | ); | 2256 | ); |
| 2250 | | 2257 | |
| | 2258 | // Additional nodes are used here, instead of just adding the sentinel |
| | 2259 | // directly to the section data, since once input sections are added |
| | 2260 | // as children, they would overwrite that data. |
| 2251 | const start_sym = start_osmi.symbol(coff).get(coff); | 2261 | const start_sym = start_osmi.symbol(coff).get(coff); |
| 2252 | try start_sym.ni.resize(&coff.mf, gpa, addr_info.size); | 2262 | const list_len_si = try coff.globalSymbol(.{ .name = list.global, .type = .data }); |
| 2253 | const start_slice = start_sym.ni.slice(&coff.mf); | 2263 | const list_len_sym = list_len_si.get(coff); |
| | 2264 | list_len_sym.setExtra(.{ .size = addr_info.size }); |
| | 2265 | list_len_sym.ni = try coff.mf.addFirstChildNode(gpa, start_sym.ni, .{ |
| | 2266 | .size = addr_info.size, |
| | 2267 | .fixed = true, |
| | 2268 | }); |
| | 2269 | coff.nodes.appendAssumeCapacity(.{ .builtin = list_len_si }); |
| | 2270 | list_len_sym.section_number = start_sym.section_number; |
| | 2271 | |
| | 2272 | const start_slice = list_len_sym.ni.slice(&coff.mf); |
| 2254 | switch (addr_info.magic) { | 2273 | switch (addr_info.magic) { |
| 2255 | _ => unreachable, | 2274 | _ => unreachable, |
| 2256 | inline .PE32, .@"PE32+" => |t| { | 2275 | inline .PE32, .@"PE32+" => |t| { |
| 2257 | const addr: *TargetAddr(t) = @ptrCast(@alignCast(start_slice)); | 2276 | const addr: *TargetAddr(t) = @ptrCast(@alignCast(start_slice)); |
| 2258 | // For __CTOR_LIST__ -1 indicates that the list is null terminated. | 2277 | // For __CTOR_LIST__ -1 indicates that the list is null terminated. |
| 2259 | // For __DTOR_LIST__, this value is ignored. | 2278 | // For __DTOR_LIST__, this value is ignored, the list is always null terminated |
| 2260 | coff.targetStore(addr, std.math.maxInt(TargetAddr(t))); | 2279 | coff.targetStore(addr, std.math.maxInt(TargetAddr(t))); |
| 2261 | }, | 2280 | }, |
| 2262 | } | 2281 | } |
| 2263 | | 2282 | |
| 2264 | // Any .(c|d)tor$(.*) input sections will merge in between these sections | | |
| 2265 | // TODO: is it guaranteed that there will be no padding between those nodes? | | |
| 2266 | | | |
| 2267 | const end_sym = end_osmi.symbol(coff).get(coff); | 2283 | const end_sym = end_osmi.symbol(coff).get(coff); |
| 2268 | try end_sym.ni.resize(&coff.mf, gpa, addr_info.size); | 2284 | const list_end_si = coff.addSymbolAssumeCapacity(); |
| 2269 | @memset(end_sym.ni.slice(&coff.mf), 0); | 2285 | const list_end_sym = list_end_si.get(coff); |
| | 2286 | list_end_sym.setExtra(.{ .size = addr_info.size }); |
| | 2287 | list_end_sym.ni = try coff.mf.addFirstChildNode(gpa, end_sym.ni, .{ |
| | 2288 | .size = addr_info.size, |
| | 2289 | .fixed = true, |
| | 2290 | }); |
| | 2291 | coff.nodes.appendAssumeCapacity(.{ .builtin = list_end_si }); |
| | 2292 | list_end_sym.section_number = start_sym.section_number; |
| 2270 | | 2293 | |
| 2271 | const list_si = try coff.globalSymbol(.{ .name = list.global, .type = .data }); | 2294 | @memset(list_end_sym.ni.slice(&coff.mf), 0); |
| 2272 | const list_sym = list_si.get(coff); | | |
| 2273 | list_sym.ni = start_sym.ni; | | |
| 2274 | list_sym.section_number = start_sym.section_number; | | |
| 2275 | | 2295 | |
| 2276 | start_sym.setExtra(.{ .next_alias_si = list_si }); | 2296 | try list_len_si.flushMoved(coff); |
| | 2297 | try list_end_si.flushMoved(coff); |
| 2277 | } | 2298 | } |
| 2278 | } | 2299 | } |
| 2279 | } | 2300 | } |
| ... | @@ -2284,7 +2305,6 @@ pub fn startProgress(coff: *Coff, prog_node: std.Progress.Node) void { | ... | @@ -2284,7 +2305,6 @@ pub fn startProgress(coff: *Coff, prog_node: std.Progress.Node) void { |
| 2284 | coff.synth_prog_node = prog_node.start("Synthetics", count: { | 2305 | coff.synth_prog_node = prog_node.start("Synthetics", count: { |
| 2285 | var count = | 2306 | var count = |
| 2286 | coff.globals.count() - coff.global_pending_index + | 2307 | coff.globals.count() - coff.global_pending_index + |
| 2287 | coff.late_globals.items.len - coff.late_globals_pending_index + | | |
| 2288 | coff.section_merges.count() - coff.section_merge_pending_index; | 2308 | coff.section_merges.count() - coff.section_merge_pending_index; |
| 2289 | | 2309 | |
| 2290 | for (&coff.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index; | 2310 | for (&coff.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index; |
| ... | @@ -2344,6 +2364,7 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 { | ... | @@ -2344,6 +2364,7 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 { |
| 2344 | .relocation_table, | 2364 | .relocation_table, |
| 2345 | .relocation_table_entry, | 2365 | .relocation_table_entry, |
| 2346 | .input_section, | 2366 | .input_section, |
| | 2367 | .builtin, |
| 2347 | => unreachable, | 2368 | => unreachable, |
| 2348 | .image_section => |si| si, | 2369 | .image_section => |si| si, |
| 2349 | .import_directory_table => break :parent_rva coff.targetLoad( | 2370 | .import_directory_table => break :parent_rva coff.targetLoad( |
| ... | @@ -2404,7 +2425,7 @@ pub inline fn targetEndian(_: *const Coff) std.lang.Endian { | ... | @@ -2404,7 +2425,7 @@ pub inline fn targetEndian(_: *const Coff) std.lang.Endian { |
| 2404 | } | 2425 | } |
| 2405 | | 2426 | |
| 2406 | fn targetAddrInfo(coff: *Coff) struct { | 2427 | fn targetAddrInfo(coff: *Coff) struct { |
| 2407 | size: u64, | 2428 | size: u8, |
| 2408 | alignment: std.mem.Alignment, | 2429 | alignment: std.mem.Alignment, |
| 2409 | magic: std.coff.OptionalHeader.Magic, | 2430 | magic: std.coff.OptionalHeader.Magic, |
| 2410 | } { | 2431 | } { |
| ... | @@ -3450,9 +3471,9 @@ fn pseudoSectionMapIndex( | ... | @@ -3450,9 +3471,9 @@ fn pseudoSectionMapIndex( |
| 3450 | } else pseudo_section_gop.value_ptr.get(coff).section_number; | 3471 | } else pseudo_section_gop.value_ptr.get(coff).section_number; |
| 3451 | | 3472 | |
| 3452 | try coff.verifyParentSectionAttributes( | 3473 | try coff.verifyParentSectionAttributes( |
| 3453 | .pseudo, | 3474 | parent_sn, |
| 3454 | parent_sn.name(coff), | | |
| 3455 | name, | 3475 | name, |
| | 3476 | .pseudo, |
| 3456 | .fromFlags(parent_sn.header(coff).flags), | 3477 | .fromFlags(parent_sn.header(coff).flags), |
| 3457 | attributes, | 3478 | attributes, |
| 3458 | ); | 3479 | ); |
| ... | @@ -3478,6 +3499,7 @@ fn objectSectionMapIndex( | ... | @@ -3478,6 +3499,7 @@ fn objectSectionMapIndex( |
| 3478 | ) !Node.ObjectSectionMapIndex { | 3499 | ) !Node.ObjectSectionMapIndex { |
| 3479 | const gpa = coff.base.comp.gpa; | 3500 | const gpa = coff.base.comp.gpa; |
| 3480 | const name_slice = name.toSlice(coff); | 3501 | const name_slice = name.toSlice(coff); |
| | 3502 | // TODO: Should this be a section merge instead? |
| 3481 | const effective_attributes = if (coff.isImage() and std.mem.startsWith(u8, name_slice, ".tls")) attr: { | 3503 | const effective_attributes = if (coff.isImage() and std.mem.startsWith(u8, name_slice, ".tls")) attr: { |
| 3482 | // In images, the .tls section is a read-only template | 3504 | // In images, the .tls section is a read-only template |
| 3483 | var attr = attributes; | 3505 | var attr = attributes; |
| ... | @@ -3541,9 +3563,9 @@ fn objectSectionMapIndex( | ... | @@ -3541,9 +3563,9 @@ fn objectSectionMapIndex( |
| 3541 | } | 3563 | } |
| 3542 | | 3564 | |
| 3543 | try coff.verifyParentSectionAttributes( | 3565 | try coff.verifyParentSectionAttributes( |
| 3544 | .object, | 3566 | sym.section_number, |
| 3545 | sym.section_number.name(coff), | | |
| 3546 | name, | 3567 | name, |
| | 3568 | .object, |
| 3547 | .fromFlags(sym.section_number.header(coff).flags), | 3569 | .fromFlags(sym.section_number.header(coff).flags), |
| 3548 | effective_attributes, | 3570 | effective_attributes, |
| 3549 | ); | 3571 | ); |
| ... | @@ -3554,21 +3576,34 @@ fn objectSectionMapIndex( | ... | @@ -3554,21 +3576,34 @@ fn objectSectionMapIndex( |
| 3554 | // TODO: Include align in attrs and verify the current align is >= requested | 3576 | // TODO: Include align in attrs and verify the current align is >= requested |
| 3555 | fn verifyParentSectionAttributes( | 3577 | fn verifyParentSectionAttributes( |
| 3556 | coff: *Coff, | 3578 | coff: *Coff, |
| 3557 | kind: enum { pseudo, object }, | 3579 | parent: Symbol.SectionNumber, |
| 3558 | parent_name: String, | | |
| 3559 | child_name: String, | 3580 | child_name: String, |
| | 3581 | child_kind: enum { pseudo, object }, |
| 3560 | parent_attrs: ObjectSectionAttributes, | 3582 | parent_attrs: ObjectSectionAttributes, |
| 3561 | child_attrs: ObjectSectionAttributes, | 3583 | child_attrs: ObjectSectionAttributes, |
| 3562 | ) !void { | 3584 | ) !void { |
| 3563 | if (parent_attrs == child_attrs) return; | 3585 | if (parent_attrs == child_attrs) return; |
| 3564 | | 3586 | |
| | 3587 | const was_merged = switch (child_kind) { |
| | 3588 | .pseudo => coff.section_merges.contains(child_name), |
| | 3589 | .object => if (coff.getString( |
| | 3590 | coff.objectSectionParentName(child_name.toSlice(coff)), |
| | 3591 | ).unwrap()) |pseudo_name| |
| | 3592 | coff.section_merges.contains(pseudo_name) |
| | 3593 | else |
| | 3594 | false, |
| | 3595 | }; |
| | 3596 | |
| | 3597 | // The section was intentionally merged by the user or builtin rule |
| | 3598 | if (was_merged) return; |
| | 3599 | |
| 3565 | const BackingT = @typeInfo(ObjectSectionAttributes).@"struct".backing_integer.?; | 3600 | const BackingT = @typeInfo(ObjectSectionAttributes).@"struct".backing_integer.?; |
| 3566 | const num_notes = @popCount(@as(BackingT, @bitCast(parent_attrs)) ^ @as(BackingT, @bitCast(child_attrs))); | 3601 | const num_notes = @popCount(@as(BackingT, @bitCast(parent_attrs)) ^ @as(BackingT, @bitCast(child_attrs))); |
| 3567 | var err = try coff.base.comp.link_diags.addErrorWithNotes(num_notes); | 3602 | var err = try coff.base.comp.link_diags.addErrorWithNotes(num_notes); |
| 3568 | try err.addMsg("{t} section '{s}' was placed in parent section '{s}' with mismatched flags", .{ | 3603 | try err.addMsg("{t} section '{s}' was placed in parent section '{s}' with mismatched flags", .{ |
| 3569 | kind, | 3604 | child_kind, |
| 3570 | child_name.toSlice(coff), | 3605 | child_name.toSlice(coff), |
| 3571 | parent_name.toSlice(coff), | 3606 | parent.name(coff).toSlice(coff), |
| 3572 | }); | 3607 | }); |
| 3573 | | 3608 | |
| 3574 | inline for (comptime std.meta.fieldNames(ObjectSectionAttributes)) |field| { | 3609 | inline for (comptime std.meta.fieldNames(ObjectSectionAttributes)) |field| { |
| ... | @@ -3578,7 +3613,7 @@ fn verifyParentSectionAttributes( | ... | @@ -3578,7 +3613,7 @@ fn verifyParentSectionAttributes( |
| 3578 | @intFromBool(@field(child_attrs, field)), | 3613 | @intFromBool(@field(child_attrs, field)), |
| 3579 | child_name.toSlice(coff), | 3614 | child_name.toSlice(coff), |
| 3580 | @intFromBool(@field(parent_attrs, field)), | 3615 | @intFromBool(@field(parent_attrs, field)), |
| 3581 | parent_name.toSlice(coff), | 3616 | parent.name(coff).toSlice(coff), |
| 3582 | }); | 3617 | }); |
| 3583 | } | 3618 | } |
| 3584 | } | 3619 | } |
| ... | @@ -4094,6 +4129,7 @@ fn loadObject( | ... | @@ -4094,6 +4129,7 @@ fn loadObject( |
| 4094 | | 4129 | |
| 4095 | // Discover symbol names and COMDAT symbol mappings | 4130 | // Discover symbol names and COMDAT symbol mappings |
| 4096 | var symbol_i: u32 = 0; | 4131 | var symbol_i: u32 = 0; |
| | 4132 | var num_included_symbols: u32 = 0; |
| 4097 | while (symbol_i < header.number_of_symbols) { | 4133 | while (symbol_i < header.number_of_symbols) { |
| 4098 | var symbol: std.coff.Symbol = undefined; | 4134 | var symbol: std.coff.Symbol = undefined; |
| 4099 | @memcpy(std.mem.asBytes(&symbol)[0..symbol_size], try r.take(symbol_size)); | 4135 | @memcpy(std.mem.asBytes(&symbol)[0..symbol_size], try r.take(symbol_size)); |
| ... | @@ -4275,6 +4311,9 @@ fn loadObject( | ... | @@ -4275,6 +4311,9 @@ fn loadObject( |
| 4275 | }; | 4311 | }; |
| 4276 | | 4312 | |
| 4277 | for (values, 0..) |value, i| { | 4313 | for (values, 0..) |value, i| { |
| | 4314 | if (section_number == .ABSOLUTE) |
| | 4315 | num_included_symbols += 1; |
| | 4316 | |
| 4278 | switch (value) { | 4317 | switch (value) { |
| 4279 | .section => {}, | 4318 | .section => {}, |
| 4280 | .static, | 4319 | .static, |
| ... | @@ -4545,12 +4584,10 @@ fn loadObject( | ... | @@ -4545,12 +4584,10 @@ fn loadObject( |
| 4545 | }; | 4584 | }; |
| 4546 | } | 4585 | } |
| 4547 | | 4586 | |
| 4548 | while (coff.section_merge_pending_index < coff.section_merges.count()) : (coff.section_merge_pending_index += 1) | 4587 | try coff.flushSectionMerges(); |
| 4549 | try coff.flushSectionMerge(coff.section_merge_pending_index); | | |
| 4550 | | 4588 | |
| 4551 | // Resolve pending associations, create parent sections | 4589 | // Resolve pending associations, create parent sections |
| 4552 | var num_included_sections: u16 = 0; | 4590 | var num_included_sections: u16 = 0; |
| 4553 | var num_included_symbols: u32 = 0; | | |
| 4554 | var num_included_relocs: u32 = 0; | 4591 | var num_included_relocs: u32 = 0; |
| 4555 | for (sections) |*section| { | 4592 | for (sections) |*section| { |
| 4556 | comdat: switch (section.comdat_result) { | 4593 | comdat: switch (section.comdat_result) { |
| ... | @@ -5916,22 +5953,6 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool { | ... | @@ -5916,22 +5953,6 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 5916 | }) coff.global_pending_index += 1; | 5953 | }) coff.global_pending_index += 1; |
| 5917 | break :task; | 5954 | break :task; |
| 5918 | } | 5955 | } |
| 5919 | if (coff.exports_complete and coff.late_globals_pending_index < coff.late_globals.items.len) { | | |
| 5920 | const gmi: Node.GlobalMapIndex = coff.late_globals.items[coff.late_globals_pending_index]; | | |
| 5921 | const sub_prog_node = coff.synth_prog_node.start( | | |
| 5922 | gmi.globalName(coff).name.toSlice(coff), | | |
| 5923 | 0, | | |
| 5924 | ); | | |
| 5925 | defer sub_prog_node.end(); | | |
| 5926 | if (coff.flushGlobal(gmi) catch |err| switch (err) { | | |
| 5927 | error.OutOfMemory => |e| return e, | | |
| 5928 | else => |e| return comp.link_diags.fail( | | |
| 5929 | "linker failed to lower constant: {t}", | | |
| 5930 | .{e}, | | |
| 5931 | ), | | |
| 5932 | }) coff.late_globals_pending_index += 1; | | |
| 5933 | break :task; | | |
| 5934 | } | | |
| 5935 | if (coff.exports_complete and coff.pending_special_symbol != .none) { | 5956 | if (coff.exports_complete and coff.pending_special_symbol != .none) { |
| 5936 | coff.pending_special_symbol = coff.flushSpecialSymbol(coff.pending_special_symbol) catch |err| | 5957 | coff.pending_special_symbol = coff.flushSpecialSymbol(coff.pending_special_symbol) catch |err| |
| 5937 | switch (err) { | 5958 | switch (err) { |
| ... | @@ -6002,7 +6023,6 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool { | ... | @@ -6002,7 +6023,6 @@ fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool { |
| 6002 | if (coff.pending_input != null) return true; | 6023 | if (coff.pending_input != null) return true; |
| 6003 | if (coff.exports_complete and coff.globals.count() > coff.global_pending_index) return true; | 6024 | if (coff.exports_complete and coff.globals.count() > coff.global_pending_index) return true; |
| 6004 | assert(!coff.exports_complete or coff.inputs_complete); | 6025 | assert(!coff.exports_complete or coff.inputs_complete); |
| 6005 | if (coff.exports_complete and coff.late_globals.items.len > coff.late_globals_pending_index) return true; | | |
| 6006 | if (coff.exports_complete and coff.pending_special_symbol != .none) return true; | 6026 | if (coff.exports_complete and coff.pending_special_symbol != .none) return true; |
| 6007 | for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; | 6027 | for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; |
| 6008 | if (coff.symbol_table.pending_symbol_index < coff.symbol_table.symbols.count()) return true; | 6028 | if (coff.symbol_table.pending_symbol_index < coff.symbol_table.symbols.count()) return true; |
| ... | @@ -6223,11 +6243,10 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { | ... | @@ -6223,11 +6243,10 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 6223 | const gpa = comp.gpa; | 6243 | const gpa = comp.gpa; |
| 6224 | const gn = gmi.globalName(coff); | 6244 | const gn = gmi.globalName(coff); |
| 6225 | const si = gmi.symbol(coff); | 6245 | const si = gmi.symbol(coff); |
| 6226 | const is_late = gmi.unwrap().? < coff.global_pending_index; | | |
| 6227 | | 6246 | |
| 6228 | log.debug( | 6247 | log.debug( |
| 6229 | "flushGlobal({s}, {?s}, {}) = n{d} {d}@{d}", | 6248 | "flushGlobal({s}, {?s}) = n{d} {d}@{d}", |
| 6230 | .{ gn.name.toSlice(coff), gn.lib_name.toSlice(coff), is_late, si.get(coff).ni, si, si.get(coff).section_number }, | 6249 | .{ gn.name.toSlice(coff), gn.lib_name.toSlice(coff), si.get(coff).ni, si, si.get(coff).section_number }, |
| 6231 | ); | 6250 | ); |
| 6232 | | 6251 | |
| 6233 | if (!coff.isImage()) { | 6252 | if (!coff.isImage()) { |
| ... | @@ -6271,7 +6290,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { | ... | @@ -6271,7 +6290,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 6271 | }; | 6290 | }; |
| 6272 | | 6291 | |
| 6273 | const opt_alt_search_name = coff.alternate_names.get(search_name); | 6292 | const opt_alt_search_name = coff.alternate_names.get(search_name); |
| 6274 | const search_libs = if (is_late) switch (sym.flags.value_tag) { | 6293 | const search_libs = switch (sym.flags.value_tag) { |
| 6275 | .weak_alias_si, .weak_alias_name => switch (sym.flags.weak_external_strat) { | 6294 | .weak_alias_si, .weak_alias_name => switch (sym.flags.weak_external_strat) { |
| 6276 | .none => unreachable, | 6295 | .none => unreachable, |
| 6277 | .no_library => false, | 6296 | .no_library => false, |
| ... | @@ -6285,18 +6304,6 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { | ... | @@ -6285,18 +6304,6 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 6285 | ), | 6304 | ), |
| 6286 | }, | 6305 | }, |
| 6287 | else => true, | 6306 | else => true, |
| 6288 | } else search_libs: { | | |
| 6289 | if (switch (sym.flags.value_tag) { | | |
| 6290 | .weak_alias_si, .weak_alias_name => true, | | |
| 6291 | else => opt_alt_search_name != null, | | |
| 6292 | }) { | | |
| 6293 | // We need to wait until all exports are known before resolving these | | |
| 6294 | coff.synth_prog_node.increaseEstimatedTotalItems(1); | | |
| 6295 | (try coff.late_globals.addOne(gpa)).* = gmi; | | |
| 6296 | return true; | | |
| 6297 | } | | |
| 6298 | | | |
| 6299 | break :search_libs true; | | |
| 6300 | }; | 6307 | }; |
| 6301 | | 6308 | |
| 6302 | const opt_indices_lists: []const ?InputArchive.SearchList = if (search_libs) &.{ | 6309 | const opt_indices_lists: []const ?InputArchive.SearchList = if (search_libs) &.{ |
| ... | @@ -6381,12 +6388,10 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { | ... | @@ -6381,12 +6388,10 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 6381 | | 6388 | |
| 6382 | switch (sym.flags.value_tag) { | 6389 | switch (sym.flags.value_tag) { |
| 6383 | .weak_alias_si => { | 6390 | .weak_alias_si => { |
| 6384 | assert(is_late); | | |
| 6385 | try coff.aliasGlobal(gmi, sym.value.weak_alias_si); | 6391 | try coff.aliasGlobal(gmi, sym.value.weak_alias_si); |
| 6386 | return true; | 6392 | return true; |
| 6387 | }, | 6393 | }, |
| 6388 | .weak_alias_name => { | 6394 | .weak_alias_name => { |
| 6389 | assert(is_late); | | |
| 6390 | // Convert an unresolved weak external that itself refers to an undef external | 6395 | // Convert an unresolved weak external that itself refers to an undef external |
| 6391 | // into a (possibly new) global, so it can be resolved separately. | 6396 | // into a (possibly new) global, so it can be resolved separately. |
| 6392 | const alias_gop = try coff.getOrPutGlobalSymbol(.{ | 6397 | const alias_gop = try coff.getOrPutGlobalSymbol(.{ |
| ... | @@ -6400,7 +6405,6 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { | ... | @@ -6400,7 +6405,6 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 6400 | | 6405 | |
| 6401 | // If there was an object that had the alternate name, we've attempted to load it | 6406 | // If there was an object that had the alternate name, we've attempted to load it |
| 6402 | if (opt_alt_search_name) |alt_search_name| { | 6407 | if (opt_alt_search_name) |alt_search_name| { |
| 6403 | assert(is_late); | | |
| 6404 | if (coff.globals.get(.{ .name = alt_search_name, .lib_name = .none })) |alias_si| { | 6408 | if (coff.globals.get(.{ .name = alt_search_name, .lib_name = .none })) |alias_si| { |
| 6405 | try coff.aliasGlobal(gmi, alias_si); | 6409 | try coff.aliasGlobal(gmi, alias_si); |
| 6406 | return true; | 6410 | return true; |
| ... | @@ -6986,6 +6990,7 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { | ... | @@ -6986,6 +6990,7 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 6986 | .lazy_code, | 6990 | .lazy_code, |
| 6987 | .lazy_const_data, | 6991 | .lazy_const_data, |
| 6988 | => |mi| try mi.symbol(coff).flushMoved(coff), | 6992 | => |mi| try mi.symbol(coff).flushMoved(coff), |
| | 6993 | .builtin => |si| try si.flushMoved(coff), |
| 6989 | } | 6994 | } |
| 6990 | try ni.childrenMoved(coff.base.comp.gpa, &coff.mf); | 6995 | try ni.childrenMoved(coff.base.comp.gpa, &coff.mf); |
| 6991 | } | 6996 | } |
| ... | @@ -7126,8 +7131,10 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { | ... | @@ -7126,8 +7131,10 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { |
| 7126 | .uav, | 7131 | .uav, |
| 7127 | .lazy_code, | 7132 | .lazy_code, |
| 7128 | .lazy_const_data, | 7133 | .lazy_const_data, |
| | 7134 | .builtin, |
| 7129 | => {}, | 7135 | => {}, |
| 7130 | .placeholder => unreachable, | 7136 | .placeholder, |
| | 7137 | => unreachable, |
| 7131 | } | 7138 | } |
| 7132 | } | 7139 | } |
| 7133 | | 7140 | |
| ... | @@ -7217,6 +7224,11 @@ fn flushExportsSort(coff: *Coff) void { | ... | @@ -7217,6 +7224,11 @@ fn flushExportsSort(coff: *Coff) void { |
| 7217 | }); | 7224 | }); |
| 7218 | } | 7225 | } |
| 7219 | | 7226 | |
| | 7227 | fn flushSectionMerges(coff: *Coff) !void { |
| | 7228 | while (coff.section_merge_pending_index < coff.section_merges.count()) : (coff.section_merge_pending_index += 1) |
| | 7229 | try coff.flushSectionMerge(coff.section_merge_pending_index); |
| | 7230 | } |
| | 7231 | |
| 7220 | fn flushSectionMerge(coff: *Coff, index: u32) !void { | 7232 | fn flushSectionMerge(coff: *Coff, index: u32) !void { |
| 7221 | assert(coff.isImage()); | 7233 | assert(coff.isImage()); |
| 7222 | const from = coff.section_merges.keys()[index]; | 7234 | const from = coff.section_merges.keys()[index]; |
| ... | @@ -7237,7 +7249,6 @@ fn flushSectionMerge(coff: *Coff, index: u32) !void { | ... | @@ -7237,7 +7249,6 @@ fn flushSectionMerge(coff: *Coff, index: u32) !void { |
| 7237 | // This is non-trivial as we can't leave holes in the section table. | 7249 | // This is non-trivial as we can't leave holes in the section table. |
| 7238 | // TODO: Merge section flags | 7250 | // TODO: Merge section flags |
| 7239 | _ = to_sym; | 7251 | _ = to_sym; |
| 7240 | | | |
| 7241 | return coff.base.comp.link_diags.fail("TODO implement section to section merge", .{}); | 7252 | return coff.base.comp.link_diags.fail("TODO implement section to section merge", .{}); |
| 7242 | } else if (coff.pseudo_section_table.get(to)) |to_ps_si| { | 7253 | } else if (coff.pseudo_section_table.get(to)) |to_ps_si| { |
| 7243 | const to_sym = to_ps_si.get(coff); | 7254 | const to_sym = to_ps_si.get(coff); |
| ... | @@ -7265,7 +7276,6 @@ fn flushSectionMerge(coff: *Coff, index: u32) !void { | ... | @@ -7265,7 +7276,6 @@ fn flushSectionMerge(coff: *Coff, index: u32) !void { |
| 7265 | // TODO: Move from_psmi's node into to_sec | 7276 | // TODO: Move from_psmi's node into to_sec |
| 7266 | // TODO: Update .section_number for all contained syms | 7277 | // TODO: Update .section_number for all contained syms |
| 7267 | // TODO: Merge section flags | 7278 | // TODO: Merge section flags |
| 7268 | | | |
| 7269 | return coff.base.comp.link_diags.fail("TODO implement pseudosection to section merge", .{}); | 7279 | return coff.base.comp.link_diags.fail("TODO implement pseudosection to section merge", .{}); |
| 7270 | } else if (coff.pseudo_section_table.get(to)) |to_ps_si| { | 7280 | } else if (coff.pseudo_section_table.get(to)) |to_ps_si| { |
| 7271 | const to_sym = to_ps_si.get(coff); | 7281 | const to_sym = to_ps_si.get(coff); |
| ... | @@ -7273,7 +7283,6 @@ fn flushSectionMerge(coff: *Coff, index: u32) !void { | ... | @@ -7273,7 +7283,6 @@ fn flushSectionMerge(coff: *Coff, index: u32) !void { |
| 7273 | return; | 7283 | return; |
| 7274 | | 7284 | |
| 7275 | // TODO: Same as above, but move from_psmi's node after to_psmi's node in its parent | 7285 | // TODO: Same as above, but move from_psmi's node after to_psmi's node in its parent |
| 7276 | | | |
| 7277 | return coff.base.comp.link_diags.fail("TODO implement pseudosection to pseudosection merge", .{}); | 7286 | return coff.base.comp.link_diags.fail("TODO implement pseudosection to pseudosection merge", .{}); |
| 7278 | } | 7287 | } |
| 7279 | | 7288 | |
| ... | @@ -7626,7 +7635,8 @@ fn printNodeName( | ... | @@ -7626,7 +7635,8 @@ fn printNodeName( |
| 7626 | inline .pseudo_section, .object_section => |smi| try w.print("({s})", .{ | 7635 | inline .pseudo_section, .object_section => |smi| try w.print("({s})", .{ |
| 7627 | smi.name(coff).toSlice(coff), | 7636 | smi.name(coff).toSlice(coff), |
| 7628 | }), | 7637 | }), |
| 7629 | .import_thunk => |gmi| { | 7638 | .import_thunk, |
| | 7639 | => |gmi| { |
| 7630 | const gn = gmi.globalName(coff); | 7640 | const gn = gmi.globalName(coff); |
| 7631 | try w.writeByte('('); | 7641 | try w.writeByte('('); |
| 7632 | if (gn.lib_name.toSlice(coff)) |lib_name| try w.print("{s}.dll, ", .{lib_name}); | 7642 | if (gn.lib_name.toSlice(coff)) |lib_name| try w.print("{s}.dll, ", .{lib_name}); |
| ... | @@ -7655,6 +7665,15 @@ fn printNodeName( | ... | @@ -7655,6 +7665,15 @@ fn printNodeName( |
| 7655 | .tid = tid, | 7665 | .tid = tid, |
| 7656 | }), | 7666 | }), |
| 7657 | }), | 7667 | }), |
| | 7668 | .builtin => |si| { |
| | 7669 | const sym = si.get(coff); |
| | 7670 | if (sym.gmi != .none) { |
| | 7671 | const gn = sym.gmi.globalName(coff); |
| | 7672 | try w.writeByte('('); |
| | 7673 | if (gn.lib_name.toSlice(coff)) |lib_name| try w.print("{s}.dll, ", .{lib_name}); |
| | 7674 | try w.print("{s})", .{gn.name.toSlice(coff)}); |
| | 7675 | } |
| | 7676 | }, |
| 7658 | } | 7677 | } |
| 7659 | } | 7678 | } |
| 7660 | | 7679 | |