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) {
796796 @".ctors$ZZZ" = 46,
797797 @".dtors" = 57,
798798 @".dtors$ZZZ" = 64,
799 @".bss" = 75,
799800 _,
800801
801802 pub const Optional = enum(u32) {
802803 @".data" = @intFromEnum(String.@".data"),
804 @".idata" = @intFromEnum(String.@".idata"),
803805 @".rdata" = @intFromEnum(String.@".rdata"),
804806 @".text" = @intFromEnum(String.@".text"),
805807 @".tls$" = @intFromEnum(String.@".tls$"),
806808 @".edata" = @intFromEnum(String.@".edata"),
809 @".ctors" = @intFromEnum(String.@".ctors"),
810 @".ctors$ZZZ" = @intFromEnum(String.@".ctors$ZZZ"),
807811 @".dtors" = @intFromEnum(String.@".dtors"),
808812 @".dtors$ZZZ" = @intFromEnum(String.@".dtors$ZZZ"),
813 @".bss" = @intFromEnum(String.@".bss"),
809814 none = std.math.maxInt(u32),
810815 _,
811816
......@@ -1000,6 +1005,7 @@ pub const Symbol = struct {
10001005
10011006 pub const Index = enum(u32) {
10021007 null,
1008 bss,
10031009 data,
10041010 rdata,
10051011 text,
......@@ -1707,7 +1713,7 @@ fn initHeaders(
17071713 var expected_nodes_len: usize = Node.known_count;
17081714 if (coff.hasCoffHeader()) {
17091715 // Sections
1710 expected_nodes_len += 3;
1716 expected_nodes_len += 4;
17111717
17121718 if (is_image)
17131719 // Pseudo-sections and import / export table
......@@ -2000,6 +2006,14 @@ fn initHeaders(
20002006
20012007 try coff.symbols.ensureTotalCapacity(gpa, Symbol.Index.known_count);
20022008 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);
20032017 assert(try coff.addSection(.@".data", .{
20042018 .CNT_INITIALIZED_DATA = true,
20052019 .MEM_READ = true,
......@@ -2021,7 +2035,7 @@ fn initHeaders(
20212035 (try coff.objectSectionMapIndex(
20222036 .@".idata",
20232037 coff.mf.flags.block_size,
2024 .{ .read = true },
2038 .{ .read = true, .initialized = true },
20252039 )).symbol(coff).node(coff),
20262040 .{ .alignment = .@"4", .moved = true },
20272041 );
......@@ -2030,7 +2044,7 @@ fn initHeaders(
20302044 coff.export_table.ni = (try coff.pseudoSectionMapIndex(
20312045 .@".edata",
20322046 .of(std.coff.ExportDirectoryTable),
2033 .{ .read = true },
2047 .{ .read = true, .initialized = true },
20342048 )).symbol(coff).node(coff);
20352049
20362050 coff.export_table.export_directory_table_ni = try coff.mf.addLastChildNode(
......@@ -2115,7 +2129,7 @@ fn initHeaders(
21152129 _ = try coff.objectSectionMapIndex(
21162130 .@".tls$",
21172131 coff.mf.flags.block_size,
2118 .{ .read = true, .write = !is_image },
2132 .{ .read = true, .write = !is_image, .initialized = true },
21192133 );
21202134 }
21212135}
......@@ -2145,12 +2159,12 @@ pub fn initBuiltins(coff: *Coff) !void {
21452159 const start_osmi = try coff.objectSectionMapIndex(
21462160 list.start,
21472161 addr_info.alignment,
2148 .{ .read = true },
2162 .{ .read = true, .initialized = true },
21492163 );
21502164 const end_osmi = try coff.objectSectionMapIndex(
21512165 list.end,
21522166 addr_info.alignment,
2153 .{ .read = true },
2167 .{ .read = true, .initialized = true },
21542168 );
21552169
21562170 const start_sym = start_osmi.symbol(coff).get(coff);
......@@ -2657,13 +2671,13 @@ fn navSection(
26572671 const ip = &zcu.intern_pool;
26582672 const default: String, const attributes: ObjectSectionAttributes =
26592673 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 },
26612675 } else if (ip.isFunctionType(nav_resolved.type)) .{
26622676 .@".text", .{ .read = true, .execute = true },
26632677 } else if (nav_resolved.@"const") .{
2664 .@".rdata", .{ .read = true },
2678 .@".rdata", .{ .read = true, .initialized = true },
26652679 } else .{
2666 .@".data", .{ .read = true, .write = true },
2680 .@".data", .{ .read = true, .write = true, .initialized = true },
26672681 };
26682682
26692683 return (try coff.objectSectionMapIndex(
......@@ -3180,6 +3194,8 @@ const ObjectSectionAttributes = packed struct {
31803194 nocache: bool = false,
31813195 discard: bool = false,
31823196 remove: bool = false,
3197 initialized: bool = false,
3198 uninitialized: bool = false,
31833199
31843200 // TODO: Include init / not init flags?
31853201
......@@ -3193,6 +3209,8 @@ const ObjectSectionAttributes = packed struct {
31933209 .nocache = flags.MEM_NOT_CACHED,
31943210 .discard = flags.MEM_DISCARDABLE,
31953211 .remove = flags.LNK_REMOVE,
3212 .initialized = flags.CNT_INITIALIZED_DATA,
3213 .uninitialized = flags.CNT_UNINITIALIZED_DATA,
31963214 };
31973215 }
31983216
......@@ -3206,6 +3224,8 @@ const ObjectSectionAttributes = packed struct {
32063224 .MEM_NOT_CACHED = attr.nocache,
32073225 .MEM_DISCARDABLE = attr.discard,
32083226 .LNK_REMOVE = attr.remove,
3227 .CNT_INITIALIZED_DATA = attr.uninitialized,
3228 .CNT_UNINITIALIZED_DATA = attr.uninitialized,
32093229 };
32103230 }
32113231};
......@@ -3220,7 +3240,9 @@ fn pseudoSectionMapIndex(
32203240 const pseudo_section_gop = try coff.pseudo_section_table.getOrPut(gpa, name);
32213241 const psmi: Node.PseudoSectionMapIndex = @enumFromInt(pseudo_section_gop.index);
32223242 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)
32243246 .text
32253247 else if (attributes.write)
32263248 .data
......@@ -3401,6 +3423,8 @@ pub fn addReloc(
34013423) !void {
34023424 const gpa = coff.base.comp.gpa;
34033425 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
34053429 const ri: Reloc.Index = @enumFromInt(coff.relocs.items.len);
34063430 log.debug("addReloc({d}@{d}+0x{x} -> {d}@{d}+0x{x}{s}) = {d}", .{
......@@ -4194,6 +4218,7 @@ fn loadObject(
41944218 const existing_crc = switch (coff.getNode(sym.ni)) {
41954219 .input_section => |isi| isi.inputSection(coff).crc,
41964220 // TODO: Should this result be cached somewhere?
4221 // TODO: Is this slice triggering has_content = true un-necessarily? Check section for init data flag.
41974222 else => std.hash.crc.Crc32Jamcrc.hash(sym.ni.slice(&coff.mf)),
41984223 };
41994224
......@@ -5750,7 +5775,7 @@ fn flushUav(
57505775 const sec_si = (try coff.objectSectionMapIndex(
57515776 .@".rdata",
57525777 coff.mf.flags.block_size,
5753 .{ .read = true },
5778 .{ .read = true, .initialized = true },
57545779 )).symbol(coff);
57555780 try coff.nodes.ensureUnusedCapacity(gpa, 1);
57565781 if (!isImage(coff)) try coff.symbol_table.pending.ensureUnusedCapacity(gpa, 1);
......@@ -6335,15 +6360,19 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
63356360 .archive_member,
63366361 => {},
63376362 .image_section => |si| {
6338 const file_offset = if (isArchive(coff))
6339 si.get(coff).ni.location(&coff.mf).resolve(&coff.mf)[0]
6340 else
6341 ni.fileLocation(&coff.mf, false).offset;
6363 const sym = si.get(coff);
6364 const flags = coff.targetLoad(&sym.section_number.header(coff).flags);
6365 if (!flags.CNT_UNINITIALIZED_DATA) {
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(
6344 &si.get(coff).section_number.header(coff).pointer_to_raw_data,
6345 @intCast(file_offset),
6346 );
6371 return coff.targetStore(
6372 &sym.section_number.header(coff).pointer_to_raw_data,
6373 @intCast(file_offset),
6374 );
6375 }
63476376 },
63486377 .input_section => |isi| {
63496378 isi.symbol(coff).flushMoved(coff);