Commit 2a994ba4a7

Jakub Konka <kubkon@jakubkonka.com>
2022-08-28 14:25:58
coff: populate missing section metadata
1 parent f36029a
Changed files (1)
src
src/link/Coff.zig
@@ -43,7 +43,9 @@ sections: std.MultiArrayList(Section) = .{},
 data_directories: [16]coff.ImageDataDirectory,
 
 text_section_index: ?u16 = null,
-got_section_index: ?u16 = null,
+rdata_section_index: ?u16 = null,
+pdata_section_index: ?u16 = null,
+data_section_index: ?u16 = null,
 
 locals: std.ArrayListUnmanaged(coff.Symbol) = .{},
 globals: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{},
@@ -212,12 +214,103 @@ fn populateMissingMetadata(self: *Coff) !void {
         const file_size = self.base.options.program_code_size_hint;
         const off = self.findFreeSpace(file_size, self.page_size); // TODO we are over-aligning in file; we should track both in file and in memory pointers
         log.debug("found .text free space 0x{x} to 0x{x}", .{ off, off + file_size });
+        var header = coff.SectionHeader{
+            .name = undefined,
+            .virtual_size = @intCast(u32, file_size),
+            .virtual_address = @intCast(u32, off),
+            .size_of_raw_data = @intCast(u32, file_size),
+            .pointer_to_raw_data = @intCast(u32, off),
+            .pointer_to_relocations = 0,
+            .pointer_to_linenumbers = 0,
+            .number_of_relocations = 0,
+            .number_of_linenumbers = 0,
+            .flags = .{
+                .CNT_CODE = 1,
+                .MEM_EXECUTE = 1,
+                .MEM_READ = 1,
+            },
+        };
+        try self.setSectionName(&header, ".text");
+        try self.sections.append(gpa, .{ .header = header });
     }
 
-    if (self.got_section_index == null) {}
+    if (self.pdata_section_index == null) {
+        self.pdata_section_index = @intCast(u16, self.sections.slice().len);
+        const file_size = self.base.options.symbol_count_hint;
+        const off = self.findFreeSpace(file_size, self.page_size);
+        log.debug("found .pdata free space 0x{x} to 0x{x}", .{ off, off + file_size });
+        var header = coff.SectionHeader{
+            .name = undefined,
+            .virtual_size = @intCast(u32, file_size),
+            .virtual_address = @intCast(u32, off),
+            .size_of_raw_data = @intCast(u32, file_size),
+            .pointer_to_raw_data = @intCast(u32, off),
+            .pointer_to_relocations = 0,
+            .pointer_to_linenumbers = 0,
+            .number_of_relocations = 0,
+            .number_of_linenumbers = 0,
+            .flags = .{
+                .CNT_INITIALIZED_DATA = 1,
+                .MEM_READ = 1,
+            },
+        };
+        try self.setSectionName(&header, ".pdata");
+        try self.sections.append(gpa, .{ .header = header });
+    }
+
+    if (self.rdata_section_index == null) {
+        self.rdata_section_index = @intCast(u16, self.sections.slice().len);
+        const file_size = 1024;
+        const off = self.findFreeSpace(file_size, self.page_size);
+        log.debug("found .rdata free space 0x{x} to 0x{x}", .{ off, off + file_size });
+        var header = coff.SectionHeader{
+            .name = undefined,
+            .virtual_size = @intCast(u32, file_size),
+            .virtual_address = @intCast(u32, off),
+            .size_of_raw_data = @intCast(u32, file_size),
+            .pointer_to_raw_data = @intCast(u32, off),
+            .pointer_to_relocations = 0,
+            .pointer_to_linenumbers = 0,
+            .number_of_relocations = 0,
+            .number_of_linenumbers = 0,
+            .flags = .{
+                .CNT_INITIALIZED_DATA = 1,
+                .MEM_READ = 1,
+            },
+        };
+        try self.setSectionName(&header, ".rdata");
+        try self.sections.append(gpa, .{ .header = header });
+    }
+
+    if (self.data_section_index == null) {
+        self.data_section_index = @intCast(u16, self.sections.slice().len);
+        const file_size = 1024;
+        const off = self.findFreeSpace(file_size, self.page_size);
+        log.debug("found .data free space 0x{x} to 0x{x}", .{ off, off + file_size });
+        var header = coff.SectionHeader{
+            .name = undefined,
+            .virtual_size = @intCast(u32, file_size),
+            .virtual_address = @intCast(u32, off),
+            .size_of_raw_data = @intCast(u32, file_size),
+            .pointer_to_raw_data = @intCast(u32, off),
+            .pointer_to_relocations = 0,
+            .pointer_to_linenumbers = 0,
+            .number_of_relocations = 0,
+            .number_of_linenumbers = 0,
+            .flags = .{
+                .CNT_INITIALIZED_DATA = 1,
+                .MEM_READ = 1,
+                .MEM_WRITE = 1,
+            },
+        };
+        try self.setSectionName(&header, ".data");
+        try self.sections.append(gpa, .{ .header = header });
+    }
 
     if (self.strtab_offset == null) {
         try self.strtab.buffer.append(gpa, 0);
+        self.strtab_offset = @intCast(u32, self.findFreeSpace(self.strtab.len(), 1));
+        log.debug("found strtab free space 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + self.strtab.len() });
     }
 
     // Index 0 is always a null symbol.
@@ -677,6 +770,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
     sub_prog_node.activate();
     defer sub_prog_node.end();
 
+    try self.writeStrtab();
     try self.writeDataDirectoriesHeaders();
     try self.writeSectionHeaders();
     try self.writeHeader();
@@ -709,6 +803,19 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v
     log.debug("TODO implement updateDeclLineNumber", .{});
 }
 
+fn writeStrtab(self: *Coff) !void {
+    const allocated_size = self.allocatedSize(self.strtab_offset.?);
+    const needed_size = self.strtab.len();
+
+    if (needed_size > allocated_size) {
+        self.strtab_offset = null;
+        self.strtab_offset = @intCast(u32, self.findFreeSpace(needed_size, 1));
+    }
+
+    log.debug("writing strtab from 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + needed_size });
+    try self.base.file.?.pwriteAll(self.strtab.buffer.items, self.strtab_offset.?);
+}
+
 fn writeSectionHeaders(self: *Coff) !void {
     const offset = self.getSectionHeadersOffset();
     try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items(.header)), offset);
@@ -729,7 +836,7 @@ fn writeHeader(self: *Coff) !void {
     writer.writeAll(msdos_stub) catch unreachable;
     writer.writeByteNTimes(0, 4) catch unreachable; // align to 8 bytes
     writer.writeAll("PE\x00\x00") catch unreachable;
-    buffer.items[0x3c] = @intCast(u8, msdos_stub.len + 4);
+    mem.writeIntLittle(u32, buffer.items[0x3c..][0..4], msdos_stub.len + 4);
 
     var flags = coff.CoffHeaderFlags{
         .EXECUTABLE_IMAGE = 1,
@@ -743,10 +850,7 @@ fn writeHeader(self: *Coff) !void {
         flags.DLL = 1;
     }
 
-    const size_of_optional_header = @intCast(
-        u16,
-        self.getOptionalHeaderSize() + self.getDataDirectoryHeadersSize() + self.getSectionHeadersSize(),
-    );
+    const size_of_optional_header = @intCast(u16, self.getOptionalHeaderSize() + self.getDataDirectoryHeadersSize());
     var coff_header = coff.CoffHeader{
         .machine = coff.MachineType.fromTargetCpuArch(self.base.options.target.cpu.arch),
         .number_of_sections = @intCast(u16, self.sections.slice().len), // TODO what if we prune a section
@@ -774,6 +878,13 @@ fn writeHeader(self: *Coff) !void {
         .Lib => default_image_base_dll,
         else => unreachable,
     };
+    const text_section = self.sections.get(self.text_section_index.?).header;
+
+    var size_of_initialized_data: u32 = 0;
+    for (self.sections.items(.header)) |header| {
+        if (header.flags.CNT_INITIALIZED_DATA == 0) continue;
+        size_of_initialized_data += header.virtual_size;
+    }
 
     switch (self.ptr_width) {
         .p32 => {
@@ -781,11 +892,11 @@ fn writeHeader(self: *Coff) !void {
                 .magic = coff.IMAGE_NT_OPTIONAL_HDR32_MAGIC,
                 .major_linker_version = 0,
                 .minor_linker_version = 0,
-                .size_of_code = 0,
-                .size_of_initialized_data = 0,
+                .size_of_code = text_section.virtual_size,
+                .size_of_initialized_data = size_of_initialized_data,
                 .size_of_uninitialized_data = 0,
                 .address_of_entry_point = self.entry_addr orelse 0,
-                .base_of_code = 0,
+                .base_of_code = text_section.virtual_address,
                 .base_of_data = 0,
                 .image_base = @intCast(u32, image_base),
                 .section_alignment = self.page_size,
@@ -816,11 +927,11 @@ fn writeHeader(self: *Coff) !void {
                 .magic = coff.IMAGE_NT_OPTIONAL_HDR64_MAGIC,
                 .major_linker_version = 0,
                 .minor_linker_version = 0,
-                .size_of_code = 0,
-                .size_of_initialized_data = 0,
+                .size_of_code = text_section.virtual_size,
+                .size_of_initialized_data = size_of_initialized_data,
                 .size_of_uninitialized_data = 0,
                 .address_of_entry_point = self.entry_addr orelse 0,
-                .base_of_code = 0,
+                .base_of_code = text_section.virtual_address,
                 .image_base = image_base,
                 .section_alignment = self.page_size,
                 .file_alignment = default_file_alignment,
@@ -971,6 +1082,7 @@ pub fn getGotAtomForSymbol(self: *Coff, sym_loc: SymbolWithLoc) ?*Atom {
 fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !void {
     if (name.len <= 8) {
         mem.copy(u8, &header.name, name);
+        mem.set(u8, header.name[name.len..], 0);
         return;
     }
     const offset = try self.strtab.insert(self.base.allocator, name);
@@ -981,6 +1093,7 @@ fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !v
 fn setSymbolName(self: *Coff, symbol: *coff.Symbol, name: []const u8) !void {
     if (name.len <= 8) {
         mem.copy(u8, &symbol.name, name);
+        mem.set(u8, symbol.name[name.len..], 0);
         return;
     }
     const offset = try self.strtab.insert(self.base.allocator, name);