authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-05 01:55:35-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-23 00:26:55-04:00
logdef87a6efb03197d2387dbbe91f02d1676427034
treed0acb0bc24ffd09d7927c5a092816e8389ce73d8
parent9325187fd212d73d39f6189241e12084a58e571b

Coff: add .bss and differentiate between initialized / uninitialized sections when merging

- Add .bss section - Set up initialized / uninitialized flags for existing sections

1 files changed, 48 insertions(+), 19 deletions(-)

src/link/Coff.zig+48-19
...@@ -796,16 +796,21 @@ pub const String = enum(u32) {...@@ -796,16 +796,21 @@ pub const String = enum(u32) {
796 @".ctors$ZZZ" = 46,796 @".ctors$ZZZ" = 46,
797 @".dtors" = 57,797 @".dtors" = 57,
798 @".dtors$ZZZ" = 64,798 @".dtors$ZZZ" = 64,
799 @".bss" = 75,
799 _,800 _,
800801
801 pub const Optional = enum(u32) {802 pub const Optional = enum(u32) {
802 @".data" = @intFromEnum(String.@".data"),803 @".data" = @intFromEnum(String.@".data"),
804 @".idata" = @intFromEnum(String.@".idata"),
803 @".rdata" = @intFromEnum(String.@".rdata"),805 @".rdata" = @intFromEnum(String.@".rdata"),
804 @".text" = @intFromEnum(String.@".text"),806 @".text" = @intFromEnum(String.@".text"),
805 @".tls$" = @intFromEnum(String.@".tls$"),807 @".tls$" = @intFromEnum(String.@".tls$"),
806 @".edata" = @intFromEnum(String.@".edata"),808 @".edata" = @intFromEnum(String.@".edata"),
809 @".ctors" = @intFromEnum(String.@".ctors"),
810 @".ctors$ZZZ" = @intFromEnum(String.@".ctors$ZZZ"),
807 @".dtors" = @intFromEnum(String.@".dtors"),811 @".dtors" = @intFromEnum(String.@".dtors"),
808 @".dtors$ZZZ" = @intFromEnum(String.@".dtors$ZZZ"),812 @".dtors$ZZZ" = @intFromEnum(String.@".dtors$ZZZ"),
813 @".bss" = @intFromEnum(String.@".bss"),
809 none = std.math.maxInt(u32),814 none = std.math.maxInt(u32),
810 _,815 _,
811816
...@@ -1000,6 +1005,7 @@ pub const Symbol = struct {...@@ -1000,6 +1005,7 @@ pub const Symbol = struct {
10001005
1001 pub const Index = enum(u32) {1006 pub const Index = enum(u32) {
1002 null,1007 null,
1008 bss,
1003 data,1009 data,
1004 rdata,1010 rdata,
1005 text,1011 text,
...@@ -1707,7 +1713,7 @@ fn initHeaders(...@@ -1707,7 +1713,7 @@ fn initHeaders(
1707 var expected_nodes_len: usize = Node.known_count;1713 var expected_nodes_len: usize = Node.known_count;
1708 if (coff.hasCoffHeader()) {1714 if (coff.hasCoffHeader()) {
1709 // Sections1715 // Sections
1710 expected_nodes_len += 3;1716 expected_nodes_len += 4;
17111717
1712 if (is_image)1718 if (is_image)
1713 // Pseudo-sections and import / export table1719 // Pseudo-sections and import / export table
...@@ -2000,6 +2006,14 @@ fn initHeaders(...@@ -2000,6 +2006,14 @@ fn initHeaders(
20002006
2001 try coff.symbols.ensureTotalCapacity(gpa, Symbol.Index.known_count);2007 try coff.symbols.ensureTotalCapacity(gpa, Symbol.Index.known_count);
2002 assert(coff.addSymbolAssumeCapacity() == .null);2008 assert(coff.addSymbolAssumeCapacity() == .null);
2009 // TODO: How do we tell MappedFile not to allocate physical space for these?
2010 // TODO: Could have a node flag 'virtual' that can never have slice* called on it or fileLocation
2011
2012 assert(try coff.addSection(.@".bss", .{
2013 .CNT_UNINITIALIZED_DATA = true,
2014 .MEM_READ = true,
2015 .MEM_WRITE = true,
2016 }) == .bss);
2003 assert(try coff.addSection(.@".data", .{2017 assert(try coff.addSection(.@".data", .{
2004 .CNT_INITIALIZED_DATA = true,2018 .CNT_INITIALIZED_DATA = true,
2005 .MEM_READ = true,2019 .MEM_READ = true,
...@@ -2021,7 +2035,7 @@ fn initHeaders(...@@ -2021,7 +2035,7 @@ fn initHeaders(
2021 (try coff.objectSectionMapIndex(2035 (try coff.objectSectionMapIndex(
2022 .@".idata",2036 .@".idata",
2023 coff.mf.flags.block_size,2037 coff.mf.flags.block_size,
2024 .{ .read = true },2038 .{ .read = true, .initialized = true },
2025 )).symbol(coff).node(coff),2039 )).symbol(coff).node(coff),
2026 .{ .alignment = .@"4", .moved = true },2040 .{ .alignment = .@"4", .moved = true },
2027 );2041 );
...@@ -2030,7 +2044,7 @@ fn initHeaders(...@@ -2030,7 +2044,7 @@ fn initHeaders(
2030 coff.export_table.ni = (try coff.pseudoSectionMapIndex(2044 coff.export_table.ni = (try coff.pseudoSectionMapIndex(
2031 .@".edata",2045 .@".edata",
2032 .of(std.coff.ExportDirectoryTable),2046 .of(std.coff.ExportDirectoryTable),
2033 .{ .read = true },2047 .{ .read = true, .initialized = true },
2034 )).symbol(coff).node(coff);2048 )).symbol(coff).node(coff);
20352049
2036 coff.export_table.export_directory_table_ni = try coff.mf.addLastChildNode(2050 coff.export_table.export_directory_table_ni = try coff.mf.addLastChildNode(
...@@ -2115,7 +2129,7 @@ fn initHeaders(...@@ -2115,7 +2129,7 @@ fn initHeaders(
2115 _ = try coff.objectSectionMapIndex(2129 _ = try coff.objectSectionMapIndex(
2116 .@".tls$",2130 .@".tls$",
2117 coff.mf.flags.block_size,2131 coff.mf.flags.block_size,
2118 .{ .read = true, .write = !is_image },2132 .{ .read = true, .write = !is_image, .initialized = true },
2119 );2133 );
2120 }2134 }
2121}2135}
...@@ -2145,12 +2159,12 @@ pub fn initBuiltins(coff: *Coff) !void {...@@ -2145,12 +2159,12 @@ pub fn initBuiltins(coff: *Coff) !void {
2145 const start_osmi = try coff.objectSectionMapIndex(2159 const start_osmi = try coff.objectSectionMapIndex(
2146 list.start,2160 list.start,
2147 addr_info.alignment,2161 addr_info.alignment,
2148 .{ .read = true },2162 .{ .read = true, .initialized = true },
2149 );2163 );
2150 const end_osmi = try coff.objectSectionMapIndex(2164 const end_osmi = try coff.objectSectionMapIndex(
2151 list.end,2165 list.end,
2152 addr_info.alignment,2166 addr_info.alignment,
2153 .{ .read = true },2167 .{ .read = true, .initialized = true },
2154 );2168 );
21552169
2156 const start_sym = start_osmi.symbol(coff).get(coff);2170 const start_sym = start_osmi.symbol(coff).get(coff);
...@@ -2657,13 +2671,13 @@ fn navSection(...@@ -2657,13 +2671,13 @@ fn navSection(
2657 const ip = &zcu.intern_pool;2671 const ip = &zcu.intern_pool;
2658 const default: String, const attributes: ObjectSectionAttributes =2672 const default: String, const attributes: ObjectSectionAttributes =
2659 if (nav_resolved.@"threadlocal" and coff.base.comp.config.any_non_single_threaded) .{2673 if (nav_resolved.@"threadlocal" and coff.base.comp.config.any_non_single_threaded) .{
2660 .@".tls$", .{ .read = true, .write = true },2674 .@".tls$", .{ .read = true, .write = true, .initialized = true },
2661 } else if (ip.isFunctionType(nav_resolved.type)) .{2675 } else if (ip.isFunctionType(nav_resolved.type)) .{
2662 .@".text", .{ .read = true, .execute = true },2676 .@".text", .{ .read = true, .execute = true },
2663 } else if (nav_resolved.@"const") .{2677 } else if (nav_resolved.@"const") .{
2664 .@".rdata", .{ .read = true },2678 .@".rdata", .{ .read = true, .initialized = true },
2665 } else .{2679 } else .{
2666 .@".data", .{ .read = true, .write = true },2680 .@".data", .{ .read = true, .write = true, .initialized = true },
2667 };2681 };
26682682
2669 return (try coff.objectSectionMapIndex(2683 return (try coff.objectSectionMapIndex(
...@@ -3180,6 +3194,8 @@ const ObjectSectionAttributes = packed struct {...@@ -3180,6 +3194,8 @@ const ObjectSectionAttributes = packed struct {
3180 nocache: bool = false,3194 nocache: bool = false,
3181 discard: bool = false,3195 discard: bool = false,
3182 remove: bool = false,3196 remove: bool = false,
3197 initialized: bool = false,
3198 uninitialized: bool = false,
31833199
3184 // TODO: Include init / not init flags?3200 // TODO: Include init / not init flags?
31853201
...@@ -3193,6 +3209,8 @@ const ObjectSectionAttributes = packed struct {...@@ -3193,6 +3209,8 @@ const ObjectSectionAttributes = packed struct {
3193 .nocache = flags.MEM_NOT_CACHED,3209 .nocache = flags.MEM_NOT_CACHED,
3194 .discard = flags.MEM_DISCARDABLE,3210 .discard = flags.MEM_DISCARDABLE,
3195 .remove = flags.LNK_REMOVE,3211 .remove = flags.LNK_REMOVE,
3212 .initialized = flags.CNT_INITIALIZED_DATA,
3213 .uninitialized = flags.CNT_UNINITIALIZED_DATA,
3196 };3214 };
3197 }3215 }
31983216
...@@ -3206,6 +3224,8 @@ const ObjectSectionAttributes = packed struct {...@@ -3206,6 +3224,8 @@ const ObjectSectionAttributes = packed struct {
3206 .MEM_NOT_CACHED = attr.nocache,3224 .MEM_NOT_CACHED = attr.nocache,
3207 .MEM_DISCARDABLE = attr.discard,3225 .MEM_DISCARDABLE = attr.discard,
3208 .LNK_REMOVE = attr.remove,3226 .LNK_REMOVE = attr.remove,
3227 .CNT_INITIALIZED_DATA = attr.uninitialized,
3228 .CNT_UNINITIALIZED_DATA = attr.uninitialized,
3209 };3229 };
3210 }3230 }
3211};3231};
...@@ -3220,7 +3240,9 @@ fn pseudoSectionMapIndex(...@@ -3220,7 +3240,9 @@ fn pseudoSectionMapIndex(
3220 const pseudo_section_gop = try coff.pseudo_section_table.getOrPut(gpa, name);3240 const pseudo_section_gop = try coff.pseudo_section_table.getOrPut(gpa, name);
3221 const psmi: Node.PseudoSectionMapIndex = @enumFromInt(pseudo_section_gop.index);3241 const psmi: Node.PseudoSectionMapIndex = @enumFromInt(pseudo_section_gop.index);
3222 const sn = if (!pseudo_section_gop.found_existing) sn: {3242 const sn = if (!pseudo_section_gop.found_existing) sn: {
3223 const default_parent: Symbol.Index = if (attributes.execute)3243 const default_parent: Symbol.Index = if (attributes.uninitialized)
3244 .bss
3245 else if (attributes.execute)
3224 .text3246 .text
3225 else if (attributes.write)3247 else if (attributes.write)
3226 .data3248 .data
...@@ -3401,6 +3423,8 @@ pub fn addReloc(...@@ -3401,6 +3423,8 @@ pub fn addReloc(
3401) !void {3423) !void {
3402 const gpa = coff.base.comp.gpa;3424 const gpa = coff.base.comp.gpa;
3403 const target = target_si.get(coff);3425 const target = target_si.get(coff);
3426 // TODO: Could duplicate the uninit flag on Symbol.flags?
3427 assert(!coff.targetLoad(loc_si.get(coff).section_number.header(coff).flags).CNT_UNINITIALIZED_DATA);
34043428
3405 const ri: Reloc.Index = @enumFromInt(coff.relocs.items.len);3429 const ri: Reloc.Index = @enumFromInt(coff.relocs.items.len);
3406 log.debug("addReloc({d}@{d}+0x{x} -> {d}@{d}+0x{x}{s}) = {d}", .{3430 log.debug("addReloc({d}@{d}+0x{x} -> {d}@{d}+0x{x}{s}) = {d}", .{
...@@ -4194,6 +4218,7 @@ fn loadObject(...@@ -4194,6 +4218,7 @@ fn loadObject(
4194 const existing_crc = switch (coff.getNode(sym.ni)) {4218 const existing_crc = switch (coff.getNode(sym.ni)) {
4195 .input_section => |isi| isi.inputSection(coff).crc,4219 .input_section => |isi| isi.inputSection(coff).crc,
4196 // TODO: Should this result be cached somewhere?4220 // TODO: Should this result be cached somewhere?
4221 // TODO: Is this slice triggering has_content = true un-necessarily? Check section for init data flag.
4197 else => std.hash.crc.Crc32Jamcrc.hash(sym.ni.slice(&coff.mf)),4222 else => std.hash.crc.Crc32Jamcrc.hash(sym.ni.slice(&coff.mf)),
4198 };4223 };
41994224
...@@ -5750,7 +5775,7 @@ fn flushUav(...@@ -5750,7 +5775,7 @@ fn flushUav(
5750 const sec_si = (try coff.objectSectionMapIndex(5775 const sec_si = (try coff.objectSectionMapIndex(
5751 .@".rdata",5776 .@".rdata",
5752 coff.mf.flags.block_size,5777 coff.mf.flags.block_size,
5753 .{ .read = true },5778 .{ .read = true, .initialized = true },
5754 )).symbol(coff);5779 )).symbol(coff);
5755 try coff.nodes.ensureUnusedCapacity(gpa, 1);5780 try coff.nodes.ensureUnusedCapacity(gpa, 1);
5756 if (!isImage(coff)) try coff.symbol_table.pending.ensureUnusedCapacity(gpa, 1);5781 if (!isImage(coff)) try coff.symbol_table.pending.ensureUnusedCapacity(gpa, 1);
...@@ -6335,15 +6360,19 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -6335,15 +6360,19 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
6335 .archive_member,6360 .archive_member,
6336 => {},6361 => {},
6337 .image_section => |si| {6362 .image_section => |si| {
6338 const file_offset = if (isArchive(coff))6363 const sym = si.get(coff);
6339 si.get(coff).ni.location(&coff.mf).resolve(&coff.mf)[0]6364 const flags = coff.targetLoad(&sym.section_number.header(coff).flags);
6340 else6365 if (!flags.CNT_UNINITIALIZED_DATA) {
6341 ni.fileLocation(&coff.mf, false).offset;6366 const file_offset = if (isArchive(coff))
6367 sym.ni.location(&coff.mf).resolve(&coff.mf)[0]
6368 else
6369 ni.fileLocation(&coff.mf, false).offset;
63426370
6343 return coff.targetStore(6371 return coff.targetStore(
6344 &si.get(coff).section_number.header(coff).pointer_to_raw_data,6372 &sym.section_number.header(coff).pointer_to_raw_data,
6345 @intCast(file_offset),6373 @intCast(file_offset),
6346 );6374 );
6375 }
6347 },6376 },
6348 .input_section => |isi| {6377 .input_section => |isi| {
6349 isi.symbol(coff).flushMoved(coff);6378 isi.symbol(coff).flushMoved(coff);