Skip to content

Commit 140bac6

Browse files
committed
link/wasm: Sort data segments
We now ensure the "bss" section is last, which allows us to not emit this section and let the runtime initialize the memory with 0's instead. This allows for smaller binaries. The order of the other segments is arbitrary and does not matter, this may change in the future.
1 parent e32a5ba commit 140bac6

File tree

1 file changed

+40
-2
lines changed

1 file changed

+40
-2
lines changed

src/link/Wasm.zig

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,6 +1255,9 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {
12551255
}
12561256

12571257
fn allocateAtoms(self: *Wasm) !void {
1258+
// first sort the data segments
1259+
try sortDataSegments(self);
1260+
12581261
var it = self.atoms.iterator();
12591262
while (it.next()) |entry| {
12601263
const segment = &self.segments.items[entry.key_ptr.*];
@@ -1278,6 +1281,36 @@ fn allocateAtoms(self: *Wasm) !void {
12781281
}
12791282
}
12801283

1284+
fn sortDataSegments(self: *Wasm) !void {
1285+
var new_mapping: std.StringArrayHashMapUnmanaged(u32) = .{};
1286+
try new_mapping.ensureUnusedCapacity(self.base.allocator, self.data_segments.count());
1287+
errdefer new_mapping.deinit(self.base.allocator);
1288+
1289+
const keys = try self.base.allocator.dupe([]const u8, self.data_segments.keys());
1290+
defer self.base.allocator.free(keys);
1291+
1292+
const SortContext = struct {
1293+
fn sort(_: void, lhs: []const u8, rhs: []const u8) bool {
1294+
return order(lhs) <= order(rhs);
1295+
}
1296+
1297+
fn order(name: []const u8) u8 {
1298+
if (mem.startsWith(u8, name, ".rodata")) return 0;
1299+
if (mem.startsWith(u8, name, ".data")) return 1;
1300+
if (mem.startsWith(u8, name, ".text")) return 2;
1301+
return 3;
1302+
}
1303+
};
1304+
1305+
std.sort.sort([]const u8, keys, {}, SortContext.sort);
1306+
for (keys) |key| {
1307+
const segment_index = self.data_segments.get(key).?;
1308+
new_mapping.putAssumeCapacity(key, segment_index);
1309+
}
1310+
self.data_segments.deinit(self.base.allocator);
1311+
self.data_segments = new_mapping;
1312+
}
1313+
12811314
fn setupImports(self: *Wasm) !void {
12821315
log.debug("Merging imports", .{});
12831316
var discarded_it = self.discarded.keyIterator();
@@ -2337,8 +2370,13 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void {
23372370
}
23382371
}
23392372
// data segments are already 'ordered'
2340-
for (self.data_segments.keys()) |key, index| {
2341-
segments.appendAssumeCapacity(.{ .index = @intCast(u32, index), .name = key });
2373+
var data_segment_index: u32 = 0;
2374+
for (self.data_segments.keys()) |key| {
2375+
// bss section is not emitted when this condition holds true, so we also
2376+
// do not output a name for it.
2377+
if (!self.base.options.import_memory and std.mem.eql(u8, key, ".bss")) continue;
2378+
segments.appendAssumeCapacity(.{ .index = data_segment_index, .name = key });
2379+
data_segment_index += 1;
23422380
}
23432381

23442382
std.sort.sort(Name, funcs.values(), {}, Name.lessThan);

0 commit comments

Comments
 (0)