Commit e32a5ba78b

Luuk de Gram <luuk@degram.dev>
2022-06-24 22:01:41
link/wasm: Put decls into the correct segments
Decls will now be put into their respective segment. e.g. a constant decl will be inserted into the "rodata" segment, whereas an uninitialized decl will be put in the "bss" segment instead.
1 parent 905a188
Changed files (2)
src
src/link/Wasm/types.zig
@@ -125,14 +125,15 @@ pub const Segment = struct {
     /// Bitfield containing flags for a segment
     flags: u32,
 
+    /// Returns the name as how it will be output into the final object
+    /// file or binary. When `merge_segments` is true, this will return the
+    /// short name. i.e. ".rodata". When false, it returns the entire name instead.
     pub fn outputName(self: Segment, merge_segments: bool) []const u8 {
         if (!merge_segments) return self.name;
         if (std.mem.startsWith(u8, self.name, ".rodata.")) {
             return ".rodata";
         } else if (std.mem.startsWith(u8, self.name, ".text.")) {
             return ".text";
-        } else if (std.mem.startsWith(u8, self.name, ".rodata.")) {
-            return ".rodata";
         } else if (std.mem.startsWith(u8, self.name, ".data.")) {
             return ".data";
         } else if (std.mem.startsWith(u8, self.name, ".bss.")) {
src/link/Wasm.zig
@@ -1143,9 +1143,29 @@ pub fn addOrUpdateImport(
     } else @panic("TODO: Implement undefined symbols for non-function declarations");
 }
 
+/// Kind represents the type of an Atom, which is only
+/// used to parse a decl into an Atom to define in which section
+/// or segment it should be placed.
 const Kind = union(enum) {
-    data: void,
+    /// Represents the segment the data symbol should
+    /// be inserted into.
+    /// TODO: Add TLS segments
+    data: enum {
+        read_only,
+        uninitialized,
+        initialized,
+    },
     function: FnData,
+
+    /// Returns the segment name the data kind represents.
+    /// Asserts `kind` has its active tag set to `data`.
+    fn segmentName(kind: Kind) []const u8 {
+        switch (kind.data) {
+            .read_only => return ".rodata.",
+            .uninitialized => return ".bss.",
+            .initialized => return ".data.",
+        }
+    }
 };
 
 /// Parses an Atom and inserts its metadata into the corresponding sections.
@@ -1174,9 +1194,8 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {
             break :result self.code_section_index.?;
         },
         .data => result: {
-            // TODO: Add mutables global decls to .bss section instead
             const segment_name = try std.mem.concat(self.base.allocator, u8, &.{
-                ".rodata.",
+                kind.segmentName(),
                 self.string_table.get(symbol.name),
             });
             errdefer self.base.allocator.free(segment_name);
@@ -1722,8 +1741,8 @@ fn populateErrorNameTable(self: *Wasm) !void {
 
     // link the atoms with the rest of the binary so they can be allocated
     // and relocations will be performed.
-    try self.parseAtom(atom, .data);
-    try self.parseAtom(names_atom, .data);
+    try self.parseAtom(atom, .{ .data = .read_only });
+    try self.parseAtom(names_atom, .{ .data = .read_only });
 }
 
 pub fn getDebugInfoIndex(self: *Wasm) !u32 {
@@ -1866,13 +1885,21 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
         const atom = &decl.*.link.wasm;
         if (decl.ty.zigTypeTag() == .Fn) {
             try self.parseAtom(atom, .{ .function = decl.fn_link.wasm });
+        } else if (decl.getVariable()) |variable| {
+            if (!variable.is_mutable) {
+                try self.parseAtom(atom, .{ .data = .read_only });
+            } else if (variable.init.isUndefDeep()) {
+                try self.parseAtom(atom, .{ .data = .uninitialized });
+            } else {
+                try self.parseAtom(atom, .{ .data = .initialized });
+            }
         } else {
-            try self.parseAtom(atom, .data);
+            try self.parseAtom(atom, .{ .data = .read_only });
         }
 
         // also parse atoms for a decl's locals
         for (atom.locals.items) |*local_atom| {
-            try self.parseAtom(local_atom, .data);
+            try self.parseAtom(local_atom, .{ .data = .read_only });
         }
     }
 
@@ -2167,7 +2194,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
         while (it.next()) |entry| {
             // do not output 'bss' section unless we import memory and therefore
             // want to guarantee the data is zero initialized
-            if (std.mem.eql(u8, entry.key_ptr.*, ".bss") and !import_memory) continue;
+            if (!import_memory and std.mem.eql(u8, entry.key_ptr.*, ".bss")) continue;
             segment_count += 1;
             const atom_index = entry.value_ptr.*;
             var atom: *Atom = self.atoms.getPtr(atom_index).?.*.getFirst();