authorgravatar for alex_naskos@hotmail.comAlexandros Naskos <alex_naskos@hotmail.com> 2020-08-30 14:51:49+03:00
committergravatar for alex_naskos@hotmail.comAlexandros Naskos <alex_naskos@hotmail.com> 2020-09-04 05:12:27+03:00
logfe0ad8d6e99746850a97266582c0437a8b51f524
treec695c6d4f709b8dd9751489e8fa41fae9386e9a3
parentfac9a4e286e90c5d5574422a17d28e85c55ae67d

Write PE section table


1 files changed, 188 insertions(+), 94 deletions(-)

src-self-hosted/link/Coff.zig+188-94
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const Coff = @This();1const Coff = @This();
22
3const std = @import("std");3const std = @import("std");
4const log = std.log.scoped(.link);
4const Allocator = std.mem.Allocator;5const Allocator = std.mem.Allocator;
5const assert = std.debug.assert;6const assert = std.debug.assert;
6const fs = std.fs;7const fs = std.fs;
...@@ -9,12 +10,9 @@ const Module = @import("../Module.zig");...@@ -9,12 +10,9 @@ const Module = @import("../Module.zig");
9const codegen = @import("../codegen/wasm.zig");10const codegen = @import("../codegen/wasm.zig");
10const link = @import("../link.zig");11const link = @import("../link.zig");
1112
12
13pub const base_tag: link.File.Tag = .coff;13pub const base_tag: link.File.Tag = .coff;
1414
15const msdos_stub = @embedFile("msdos-stub.bin");15const msdos_stub = @embedFile("msdos-stub.bin");
16const coff_file_header_offset = msdos_stub.len + 4;
17const optional_header_offset = coff_file_header_offset + 20;
1816
19base: link.File,17base: link.File,
20ptr_width: enum { p32, p64 },18ptr_width: enum { p32, p64 },
...@@ -70,8 +68,7 @@ fn openFile(allocator: *Allocator, file: fs.File, options: link.Options) !Coff {...@@ -70,8 +68,7 @@ fn openFile(allocator: *Allocator, file: fs.File, options: link.Options) !Coff {
70/// Returns an error if `file` is not already open with +read +write +seek abilities.68/// Returns an error if `file` is not already open with +read +write +seek abilities.
71fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !Coff {69fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !Coff {
72 switch (options.output_mode) {70 switch (options.output_mode) {
73 .Exe => {},71 .Exe, .Obj => {},
74 .Obj => return error.TODOImplementWritingObjFiles, // @TODO DO OBJ FILES
75 .Lib => return error.TODOImplementWritingLibFiles,72 .Lib => return error.TODOImplementWritingLibFiles,
76 }73 }
77 var self: Coff = .{74 var self: Coff = .{
...@@ -91,108 +88,205 @@ fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !Coff...@@ -91,108 +88,205 @@ fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !Coff
91 };88 };
92 errdefer self.deinit();89 errdefer self.deinit();
9390
94 var output = self.base.file.?.writer();91 var coff_file_header_offset: u32 = 0;
92 if (options.output_mode == .Exe) {
93 // Write the MS-DOS stub and the PE signature
94 try self.base.file.?.pwriteAll(msdos_stub ++ "PE\x00\x00", 0);
95 coff_file_header_offset = msdos_stub.len + 4;
96 }
97
98 // COFF file header
99 const data_directory_count = 0;
100 var hdr_data: [112 + data_directory_count * 8 + 2 * 40]u8 = undefined;
101 var index: usize = 0;
95102
96 // MS-DOS stub + PE magic103 // @TODO Add an enum(u16) in std.coff, add .toCoffMachine to Arch
97 try output.writeAll(msdos_stub ++ "PE\x00\x00");
98 const machine_type: u16 = switch (self.base.options.target.cpu.arch) {104 const machine_type: u16 = switch (self.base.options.target.cpu.arch) {
99 .x86_64 => 0x8664,105 .x86_64 => 0x8664,
100 .i386 => 0x014c,106 .i386 => 0x014c,
101 .riscv32 => 0x5032,107 .riscv32 => 0x5032,
102 .riscv64 => 0x5064,108 .riscv64 => 0x5064,
103 else => return error.UnsupportedCOFFArchitecture,109 else => return error.UnsupportedCOFFArchitecture,
104 };110 };
111 std.mem.writeIntLittle(u16, hdr_data[0..2], machine_type);
112 index += 2;
113
114 // Number of sections (we only use .got, .text)
115 std.mem.writeIntLittle(u16, hdr_data[index..][0..2], 2);
116 index += 2;
117 // TimeDateStamp (u32), PointerToSymbolTable (u32), NumberOfSymbols (u32)
118 std.mem.set(u8, hdr_data[index..][0..12], 0);
119 index += 12;
120
121 const optional_header_size = switch (options.output_mode) {
122 .Exe => data_directory_count * 8 + switch (self.ptr_width) {
123 .p32 => @as(u16, 96),
124 .p64 => 112,
125 },
126 else => 0,
127 };
128 std.mem.writeIntLittle(u16, hdr_data[index..][0..2], optional_header_size);
129 index += 2;
105130
106 // Start of COFF file header131 // Characteristics - IMAGE_FILE_DEBUG_STRIPPED
107 try output.writeIntLittle(u16, machine_type);132 var characteristics: u16 = 0x200; // TODO Remove debug info stripped flag when necessary
108 try output.writeIntLittle(u16, switch (self.ptr_width) {133 if (options.output_mode == .Exe) {
109 .p32 => @as(u16, 98),134 // IMAGE_FILE_EXECUTABLE_IMAGE
110 .p64 => 114,135 characteristics |= 0x2;
111 });136 }
112 try output.writeAll("\x00" ** 14);
113 // Characteristics - IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED
114 var characteristics: u16 = 0x0001 | 0x000 | 0x02002; // @TODO Remove debug info stripped flag when necessary
115 switch (self.ptr_width) {137 switch (self.ptr_width) {
116 // IMAGE_FILE_32BIT_MACHINE138 // IMAGE_FILE_32BIT_MACHINE
117 .p32 => characteristics |= 0x0100,139 .p32 => characteristics |= 0x100,
118 // IMAGE_FILE_LARGE_ADDRESS_AWARE140 // IMAGE_FILE_LARGE_ADDRESS_AWARE
119 .p64 => characteristics |= 0x0020,141 .p64 => characteristics |= 0x20,
120 }
121 try output.writeIntLittle(u16, characteristics);
122 try output.writeIntLittle(u16, switch (self.ptr_width) {
123 .p32 => @as(u16, 0x10b),
124 .p64 => 0x20b,
125 });
126
127 // Start of optional header
128 // TODO Linker version, use 0.0 for now.
129 try output.writeAll("\x00" ** 2);
130 // Zero out every field until "BaseOfCode"
131 // @TODO Actually write entry point address, base of code address
132 try output.writeAll("\x00" ** 20);
133 switch (self.ptr_width) {
134 .p32 => {
135 // Zero out base of data
136 try output.writeAll("\x00" ** 4);
137 // Write image base
138 try output.writeIntLittle(u32, 0x40000000);
139 },
140 .p64 => {
141 // Write image base
142 try output.writeIntLittle(u64, 0x40000000);
143 },
144 }142 }
143 std.mem.writeIntLittle(u16, hdr_data[index..][0..2], characteristics);
144 index += 2;
145145
146 // Section alignment - default to 256146 assert(index == 20);
147 try output.writeIntLittle(u32, 256);147 try self.base.file.?.pwriteAll(hdr_data[0..index], coff_file_header_offset);
148 // File alignment - default to 512148
149 try output.writeIntLittle(u32, 512);149 if (options.output_mode == .Exe) {
150 // TODO - Minimum required windows version - use 6.0 (aka vista for now)150 // Optional header
151 try output.writeIntLittle(u16, 0x6);151 index = 0;
152 try output.writeIntLittle(u16, 0x0);152 std.mem.writeIntLittle(u16, hdr_data[0..2], switch (self.ptr_width) {
153 // TODO - Image version - use 0.0 for now153 .p32 => @as(u16, 0x10b),
154 try output.writeIntLittle(u32, 0x0);154 .p64 => 0x20b,
155 // Subsystem version155 });
156 try output.writeIntLittle(u16, 0x6);156 index += 2;
157 try output.writeIntLittle(u16, 0x0);157
158 // Reserved zeroes158 // Linker version (u8 + u8), SizeOfCode (u32), SizeOfInitializedData (u32), SizeOfUninitializedData (u32), AddressOfEntryPoint (u32)
159 try output.writeIntLittle(u32, 0x0);159 std.mem.set(u8, hdr_data[index..][0..18], 0);
160 // Size of image - initialize to zero160 index += 18;
161 try output.writeIntLittle(u32, 0x0);161
162 // @TODO Size of headers - calculate this.162 // Base of code relative to the image base
163 try output.writeIntLittle(u32, 0x0);163 // @TODO Check where to put this
164 // Checksum164 std.mem.writeIntLittle(u32, hdr_data[index..][0..4], 0x1000);
165 try output.writeIntLittle(u32, 0x0);165 index += 4;
166 // Subsystem166
167 try output.writeIntLittle(u16, 0x3);167 if (self.ptr_width == .p32) {
168 // @TODO Dll characteristics, just using a value from a LLVM produced executable for now.168 // Base of data relative to the image base
169 try output.writeIntLittle(u16, 0x8160);169 std.mem.set(u8, hdr_data[index..][0..4], 0);
170 switch (self.ptr_width) {170 index += 4;
171 .p32 => {171
172 // Stack reserve172 // Image base address
173 try output.writeIntLittle(u32, 0x1000000);173 std.mem.writeIntLittle(u32, hdr_data[index..][0..4], 0x400_000);
174 // Stack commit174 index += 4;
175 try output.writeIntLittle(u32, 0x1000);175 } else {
176 // Heap reserve176 // Image base address
177 try output.writeIntLittle(u32, 0x100000);177 std.mem.writeIntLittle(u64, hdr_data[index..][0..8], 0x140_000_000);
178 // Heap commit178 index += 8;
179 try output.writeIntLittle(u32, 0x100);179 }
180 },180
181 .p64 => {181 // Section alignment
182 // Stack reserve182 std.mem.writeIntLittle(u32, hdr_data[index..][0..4], 4096);
183 try output.writeIntLittle(u64, 0x1000000);183 index += 4;
184 // Stack commit184 // File alignment
185 try output.writeIntLittle(u64, 0x1000);185 std.mem.writeIntLittle(u32, hdr_data[index..][0..4], 512);
186 // Heap reserve186 index += 4;
187 try output.writeIntLittle(u64, 0x100000);187 // Required OS version, 6.0 is vista
188 // Heap commit188 std.mem.writeIntLittle(u16, hdr_data[index..][0..2], 6);
189 try output.writeIntLittle(u64, 0x100);189 index += 2;
190 },190 std.mem.writeIntLittle(u16, hdr_data[index..][0..2], 0);
191 index += 2;
192 // Image version
193 std.mem.set(u8, hdr_data[index..][0..4], 0);
194 index += 4;
195 // Required subsystem version, same as OS version
196 std.mem.writeIntLittle(u16, hdr_data[index..][0..2], 6);
197 index += 2;
198 std.mem.writeIntLittle(u16, hdr_data[index..][0..2], 0);
199 index += 2;
200 // Reserved zeroes (u32), SizeOfImage (u32), SizeOfHeaders (u32), CheckSum (u32)
201 std.mem.set(u8, hdr_data[index..][0..16], 0);
202 index += 16;
203 // Subsystem, TODO: Let users specify the subsystem, always CUI for now
204 std.mem.writeIntLittle(u16, hdr_data[index..][0..2], 3);
205 index += 2;
206 // DLL characteristics, TODO: For now we are just using IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
207 std.mem.writeIntLittle(u16, hdr_data[index..][0..2], 0x40);
208 index += 2;
209
210 switch (self.ptr_width) {
211 .p32 => {
212 // @TODO See llvm output for 32 bit executables
213 // Size of stack reserve + commit
214 std.mem.writeIntLittle(u32, hdr_data[index..][0..4], 0x1_000_000);
215 index += 4;
216 std.mem.writeIntLittle(u32, hdr_data[index..][0..4], 0x1_000);
217 index += 4;
218 // Size of heap reserve + commit
219 std.mem.writeIntLittle(u32, hdr_data[index..][0..4], 0x100_000);
220 index += 4;
221 std.mem.writeIntLittle(u32, hdr_data[index..][0..4], 0x1_000);
222 index += 4;
223 },
224 .p64 => {
225 // Size of stack reserve + commit
226 std.mem.writeIntLittle(u64, hdr_data[index..][0..8], 0x1_000_000);
227 index += 8;
228 std.mem.writeIntLittle(u64, hdr_data[index..][0..8], 0x1_000);
229 index += 8;
230 // Size of heap reserve + commit
231 std.mem.writeIntLittle(u64, hdr_data[index..][0..8], 0x100_000);
232 index += 8;
233 std.mem.writeIntLittle(u64, hdr_data[index..][0..8], 0x1_000);
234 index += 8;
235 },
236 }
237
238 // Reserved zeroes
239 std.mem.set(u8, hdr_data[index..][0..4], 0);
240 index += 4;
241
242 // Number of data directories
243 std.mem.writeIntLittle(u32, hdr_data[index..][0..4], data_directory_count);
244 index += 4;
245 // @TODO Write meaningful stuff here
246 // Initialize data directories to zero
247 std.mem.set(u8, hdr_data[index..][0..data_directory_count * 8], 0);
248 index += data_directory_count * 8;
249
250 assert(index == optional_header_size);
191 }251 }
192 // Reserved loader flags252
193 try output.writeIntLittle(u32, 0x0);253 // @TODO Merge this write with the one above
194 // Number of RVA + sizes254 const section_table_offset = coff_file_header_offset + 20 + optional_header_size;
195 try output.writeIntLittle(u32, 0x0);255
256 // Write section table.
257 // First, the .got section
258 hdr_data[index..][0..8].* = ".got\x00\x00\x00\x00".*;
259 index += 8;
260 // Virtual size (u32) (@TODO Set to initial value in image files, zero otherwise), Virtual address (u32) (@TODO Set to value in image files, zero otherwise), Size of raw data (u32)
261 std.mem.set(u8, hdr_data[index..][0..12], 0);
262 index += 12;
263 // File pointer to the start of the section
264 std.mem.writeIntLittle(u32, hdr_data[index..][0..4], section_table_offset + 2 * 40);
265 index += 4;
266 // Pointer to relocations (u32) (@TODO Initialize this for object files), PointerToLinenumbers (u32), NumberOfRelocations (u16), (@TODO Initialize this for object files), NumberOfLinenumbers (u16)
267 std.mem.set(u8, hdr_data[index..][0..12], 0);
268 index += 12;
269 // Characteristics `IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ = 0x40000040`
270 std.mem.writeIntLittle(u32, hdr_data[index..][0..4], 0x40000040);
271 index += 4;
272 // Then, the .text section
273 hdr_data[index..][0..8].* = ".text\x00\x00\x00".*;
274 index += 8;
275 // Virtual size (u32) (@TODO Set to initial value in image files, zero otherwise), Virtual address (u32) (@TODO Set to value in image files, zero otherwise), Size of raw data (u32)
276 std.mem.set(u8, hdr_data[index..][0..12], 0);
277 index += 12;
278 // File pointer to the start of the section (@TODO Add the initial size of .got)
279 std.mem.writeIntLittle(u32, hdr_data[index..][0..4], section_table_offset + 2 * 40);
280 index += 4;
281 // Pointer to relocations (u32) (@TODO Initialize this for object files), PointerToLinenumbers (u32), NumberOfRelocations (u16), (@TODO Initialize this for object files), NumberOfLinenumbers (u16)
282 std.mem.set(u8, hdr_data[index..][0..12], 0);
283 index += 12;
284 // Characteristics `IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE = 0xE0000020`
285 std.mem.writeIntLittle(u32, hdr_data[index..][0..4], 0xE0000020);
286 index += 4;
287
288 assert(index == optional_header_size + 2 * 40);
289 try self.base.file.?.pwriteAll(hdr_data[0..index], coff_file_header_offset + 20);
196290
197 return self;291 return self;
198}292}