authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-10-04 17:48:07-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-10-04 17:59:44-07:00
log1d777e99588be047ec4d7650f048b043d6e52da0
treec6155fb3f8b3d9f6218942bbce293bab355d2bf8
parentda596b7e4febc95ec5249c9f489166944fbe69b9

add --image-base support

Based on #6121 by Jay Petacat.

6 files changed, 64 insertions(+), 19 deletions(-)

lib/std/build.zig+8
......@@ -1232,6 +1232,9 @@ pub const LibExeObjStep = struct {
12321232 installed_path: ?[]const u8,
12331233 install_step: ?*InstallArtifactStep,
12341234
1235 /// Base address for an executable image.
1236 image_base: ?u64 = null,
1237
12351238 libc_file: ?[]const u8 = null,
12361239
12371240 valgrind_support: ?bool = null,
......@@ -2041,6 +2044,11 @@ pub const LibExeObjStep = struct {
20412044 try zig_args.append("--pkg-end");
20422045 }
20432046
2047 if (self.image_base) |image_base| {
2048 try zig_args.append("--image-base");
2049 try zig_args.append(image_base);
2050 }
2051
20442052 if (self.filter) |filter| {
20452053 try zig_args.append("--test-filter");
20462054 try zig_args.append(filter);
src/Compilation.zig+3
......@@ -378,6 +378,7 @@ pub const InitOptions = struct {
378378 is_compiler_rt_or_libc: bool = false,
379379 parent_compilation_link_libc: bool = false,
380380 stack_size_override: ?u64 = null,
381 image_base_override: ?u64 = null,
381382 self_exe_path: ?[]const u8 = null,
382383 version: ?std.builtin.Version = null,
383384 libc_installation: ?*const LibCInstallation = null,
......@@ -452,6 +453,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
452453 options.link_emit_relocs or
453454 options.output_mode == .Lib or
454455 options.lld_argv.len != 0 or
456 options.image_base_override != null or
455457 options.linker_script != null or options.version_script != null)
456458 {
457459 break :blk true;
......@@ -772,6 +774,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
772774 .z_nodelete = options.linker_z_nodelete,
773775 .z_defs = options.linker_z_defs,
774776 .stack_size_override = options.stack_size_override,
777 .image_base_override = options.image_base_override,
775778 .linker_script = options.linker_script,
776779 .version_script = options.version_script,
777780 .gc_sections = options.linker_gc_sections,
src/link.zig+1
......@@ -45,6 +45,7 @@ pub const Options = struct {
4545 program_code_size_hint: u64 = 256 * 1024,
4646 entry_addr: ?u64 = null,
4747 stack_size_override: ?u64,
48 image_base_override: ?u64,
4849 /// Set to `true` to omit debug info.
4950 strip: bool,
5051 /// If this is true then this link code is responsible for outputting an object
src/link/Coff.zig+17-13
......@@ -22,10 +22,10 @@ const minimum_text_block_size = 64 * allocation_padding;
2222
2323const section_alignment = 4096;
2424const file_alignment = 512;
25const image_base = 0x400_000;
25const default_image_base = 0x400_000;
2626const section_table_size = 2 * 40;
2727comptime {
28 assert(mem.isAligned(image_base, section_alignment));
28 assert(mem.isAligned(default_image_base, section_alignment));
2929}
3030
3131pub const base_tag: link.File.Tag = .coff;
......@@ -55,7 +55,7 @@ offset_table: std.ArrayListUnmanaged(u64) = .{},
5555/// Free list of offset table indices
5656offset_table_free_list: std.ArrayListUnmanaged(u32) = .{},
5757
58/// Virtual address of the entry point procedure relative to `image_base`
58/// Virtual address of the entry point procedure relative to image base.
5959entry_addr: ?u32 = null,
6060
6161/// Absolute virtual address of the text section when the executable is loaded in memory.
......@@ -183,14 +183,14 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
183183
184184 self.section_data_offset = mem.alignForwardGeneric(u32, self.section_table_offset + section_table_size, file_alignment);
185185 const section_data_relative_virtual_address = mem.alignForwardGeneric(u32, self.section_table_offset + section_table_size, section_alignment);
186 self.offset_table_virtual_address = image_base + section_data_relative_virtual_address;
186 self.offset_table_virtual_address = default_image_base + section_data_relative_virtual_address;
187187 self.offset_table_size = default_offset_table_size;
188188 self.section_table_offset = section_table_offset;
189 self.text_section_virtual_address = image_base + section_data_relative_virtual_address + section_alignment;
189 self.text_section_virtual_address = default_image_base + section_data_relative_virtual_address + section_alignment;
190190 self.text_section_size = default_size_of_code;
191191
192192 // Size of file when loaded in memory
193 const size_of_image = mem.alignForwardGeneric(u32, self.text_section_virtual_address - image_base + default_size_of_code, section_alignment);
193 const size_of_image = mem.alignForwardGeneric(u32, self.text_section_virtual_address - default_image_base + default_size_of_code, section_alignment);
194194
195195 mem.writeIntLittle(u16, hdr_data[index..][0..2], optional_header_size);
196196 index += 2;
......@@ -234,11 +234,11 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
234234 index += 4;
235235
236236 // Image base address
237 mem.writeIntLittle(u32, hdr_data[index..][0..4], image_base);
237 mem.writeIntLittle(u32, hdr_data[index..][0..4], default_image_base);
238238 index += 4;
239239 } else {
240240 // Image base address
241 mem.writeIntLittle(u64, hdr_data[index..][0..8], image_base);
241 mem.writeIntLittle(u64, hdr_data[index..][0..8], default_image_base);
242242 index += 8;
243243 }
244244
......@@ -328,7 +328,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
328328 mem.writeIntLittle(u32, hdr_data[index..][0..4], default_offset_table_size);
329329 index += 4;
330330 // Virtual address (u32)
331 mem.writeIntLittle(u32, hdr_data[index..][0..4], self.offset_table_virtual_address - image_base);
331 mem.writeIntLittle(u32, hdr_data[index..][0..4], self.offset_table_virtual_address - default_image_base);
332332 index += 4;
333333 } else {
334334 mem.set(u8, hdr_data[index..][0..8], 0);
......@@ -354,7 +354,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
354354 mem.writeIntLittle(u32, hdr_data[index..][0..4], default_size_of_code);
355355 index += 4;
356356 // Virtual address (u32)
357 mem.writeIntLittle(u32, hdr_data[index..][0..4], self.text_section_virtual_address - image_base);
357 mem.writeIntLittle(u32, hdr_data[index..][0..4], self.text_section_virtual_address - default_image_base);
358358 index += 4;
359359 } else {
360360 mem.set(u8, hdr_data[index..][0..8], 0);
......@@ -601,7 +601,7 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {
601601
602602 // Write .text new virtual address
603603 self.text_section_virtual_address = self.text_section_virtual_address + va_offset;
604 mem.writeIntLittle(u32, buf[0..4], self.text_section_virtual_address - image_base);
604 mem.writeIntLittle(u32, buf[0..4], self.text_section_virtual_address - default_image_base);
605605 try self.base.file.?.pwriteAll(buf[0..4], self.section_table_offset + 40 + 12);
606606
607607 // Fix the VAs in the offset table
......@@ -716,7 +716,7 @@ pub fn updateDeclExports(self: *Coff, module: *Module, decl: *const Module.Decl,
716716 }
717717 }
718718 if (mem.eql(u8, exp.options.name, "_start")) {
719 self.entry_addr = decl.link.coff.getVAddr(self.*) - image_base;
719 self.entry_addr = decl.link.coff.getVAddr(self.*) - default_image_base;
720720 } else {
721721 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
722722 module.failed_exports.putAssumeCapacityNoClobber(
......@@ -754,7 +754,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation) !void {
754754 }
755755
756756 if (self.base.options.output_mode == .Exe and self.size_of_image_dirty) {
757 const new_size_of_image = mem.alignForwardGeneric(u32, self.text_section_virtual_address - image_base + self.text_section_size, section_alignment);
757 const new_size_of_image = mem.alignForwardGeneric(u32, self.text_section_virtual_address - default_image_base + self.text_section_size, section_alignment);
758758 var buf: [4]u8 = undefined;
759759 mem.writeIntLittle(u32, &buf, new_size_of_image);
760760 try self.base.file.?.pwriteAll(&buf, self.optional_header_offset + 56);
......@@ -832,6 +832,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
832832 }
833833 try man.addOptionalFile(module_obj_path);
834834 man.hash.addOptional(self.base.options.stack_size_override);
835 man.hash.addOptional(self.base.options.image_base_override);
835836 man.hash.addListOfBytes(self.base.options.extra_lld_args);
836837 man.hash.addListOfBytes(self.base.options.lib_dirs);
837838 man.hash.add(self.base.options.is_compiler_rt_or_libc);
......@@ -914,6 +915,9 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
914915 const stack_size = self.base.options.stack_size_override orelse 16777216;
915916 try argv.append(try allocPrint(arena, "-STACK:{d}", .{stack_size}));
916917 }
918 if (self.base.options.image_base_override) |image_base| {
919 try argv.append(try std.fmt.allocPrint(arena, "-BASE:{d}", .{image_base}));
920 }
917921
918922 if (target.cpu.arch == .i386) {
919923 try argv.append("-MACHINE:X86");
src/link/Elf.zig+5
......@@ -1284,6 +1284,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
12841284 // We can skip hashing libc and libc++ components that we are in charge of building from Zig
12851285 // installation sources because they are always a product of the compiler version + target information.
12861286 man.hash.add(stack_size);
1287 man.hash.addOptional(self.base.options.image_base_override);
12871288 man.hash.add(gc_sections);
12881289 man.hash.add(self.base.options.eh_frame_hdr);
12891290 man.hash.add(self.base.options.emit_relocs);
......@@ -1353,6 +1354,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
13531354 try argv.append(try std.fmt.allocPrint(arena, "stack-size={}", .{stack_size}));
13541355 }
13551356
1357 if (self.base.options.image_base_override) |image_base| {
1358 try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{image_base}));
1359 }
1360
13561361 if (self.base.options.linker_script) |linker_script| {
13571362 try argv.append("-T");
13581363 try argv.append(linker_script);
src/main.zig+30-6
......@@ -279,6 +279,7 @@ const usage_build_generic =
279279 \\ -Bsymbolic Bind global references locally
280280 \\ --subsystem [subsystem] (windows) /SUBSYSTEM:<subsystem> to the linker\n"
281281 \\ --stack [size] Override default stack size
282 \\ --image-base [addr] Set base address for executable image
282283 \\ -framework [name] (darwin) link against framework
283284 \\ -F[dir] (darwin) add search path for frameworks
284285 \\
......@@ -435,6 +436,7 @@ fn buildOutputType(
435436 var linker_z_defs = false;
436437 var test_evented_io = false;
437438 var stack_size_override: ?u64 = null;
439 var image_base_override: ?u64 = null;
438440 var use_llvm: ?bool = null;
439441 var use_lld: ?bool = null;
440442 var use_clang: ?bool = null;
......@@ -628,9 +630,11 @@ fn buildOutputType(
628630 } else if (mem.eql(u8, arg, "--stack")) {
629631 if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
630632 i += 1;
631 stack_size_override = std.fmt.parseInt(u64, args[i], 10) catch |err| {
632 fatal("unable to parse '{}': {}", .{ arg, @errorName(err) });
633 };
633 stack_size_override = parseAnyBaseInt(args[i]);
634 } else if (mem.eql(u8, arg, "--image-base")) {
635 if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
636 i += 1;
637 image_base_override = parseAnyBaseInt(args[i]);
634638 } else if (mem.eql(u8, arg, "--name")) {
635639 if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
636640 i += 1;
......@@ -1147,9 +1151,13 @@ fn buildOutputType(
11471151 if (i >= linker_args.items.len) {
11481152 fatal("expected linker arg after '{}'", .{arg});
11491153 }
1150 stack_size_override = std.fmt.parseInt(u64, linker_args.items[i], 10) catch |err| {
1151 fatal("unable to parse '{}': {}", .{ arg, @errorName(err) });
1152 };
1154 stack_size_override = parseAnyBaseInt(linker_args.items[i]);
1155 } else if (mem.eql(u8, arg, "--image-base")) {
1156 i += 1;
1157 if (i >= linker_args.items.len) {
1158 fatal("expected linker arg after '{}'", .{arg});
1159 }
1160 image_base_override = parseAnyBaseInt(linker_args.items[i]);
11531161 } else {
11541162 warn("unsupported linker arg: {}", .{arg});
11551163 }
......@@ -1595,6 +1603,7 @@ fn buildOutputType(
15951603 .link_eh_frame_hdr = link_eh_frame_hdr,
15961604 .link_emit_relocs = link_emit_relocs,
15971605 .stack_size_override = stack_size_override,
1606 .image_base_override = image_base_override,
15981607 .strip = strip,
15991608 .single_threaded = single_threaded,
16001609 .function_sections = function_sections,
......@@ -3051,3 +3060,18 @@ pub fn cleanExit() void {
30513060 process.exit(0);
30523061 }
30533062}
3063
3064fn parseAnyBaseInt(prefixed_bytes: []const u8) u64 {
3065 const base: u8 = if (mem.startsWith(u8, prefixed_bytes, "0x"))
3066 16
3067 else if (mem.startsWith(u8, prefixed_bytes, "0o"))
3068 8
3069 else if (mem.startsWith(u8, prefixed_bytes, "0b"))
3070 2
3071 else
3072 @as(u8, 10);
3073 const bytes = if (base == 10) prefixed_bytes else prefixed_bytes[2..];
3074 return std.fmt.parseInt(u64, bytes, base) catch |err| {
3075 fatal("unable to parse '{}': {}", .{ prefixed_bytes, @errorName(err) });
3076 };
3077}