authorgravatar for hannesbredberg@gmail.comN00byEdge <hannesbredberg@gmail.com> 2021-12-03 14:53:24+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-03 16:42:02-08:00
log9354ad82782f72a05663b64fcfd839d2aa98e878
tree0d876bd27307aab938621daa46cd3f8dd6ed0e4a
parent3311ef3262c6d650d7ef23ad62ae0483835f79c4

Add single section dumping and padding to InstallRawStep


2 files changed, 104 insertions(+), 20 deletions(-)

lib/std/build.zig+6-4
......@@ -1018,8 +1018,10 @@ pub const Builder = struct {
10181018 }
10191019
10201020 /// Output format (BIN vs Intel HEX) determined by filename
1021 pub fn installRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) void {
1022 self.getInstallStep().dependOn(&self.addInstallRaw(artifact, dest_filename, options).step);
1021 pub fn installRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep {
1022 const raw = self.addInstallRaw(artifact, dest_filename, options);
1023 self.getInstallStep().dependOn(&raw.step);
1024 return raw;
10231025 }
10241026
10251027 ///`dest_rel_path` is relative to install prefix path
......@@ -1732,8 +1734,8 @@ pub const LibExeObjStep = struct {
17321734 self.builder.installArtifact(self);
17331735 }
17341736
1735 pub fn installRaw(self: *LibExeObjStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) void {
1736 self.builder.installRaw(self, dest_filename, options);
1737 pub fn installRaw(self: *LibExeObjStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep {
1738 return self.builder.installRaw(self, dest_filename, options);
17371739 }
17381740
17391741 /// Creates a `RunStep` with an executable built with `addExecutable`.
lib/std/build/InstallRawStep.zig+98-16
......@@ -2,7 +2,7 @@ const std = @import("std");
22
33const Allocator = std.mem.Allocator;
44const ArenaAllocator = std.heap.ArenaAllocator;
5const ArrayList = std.ArrayList;
5const ArrayListUnmanaged = std.ArrayListUnmanaged;
66const Builder = std.build.Builder;
77const File = std.fs.File;
88const InstallDir = std.build.InstallDir;
......@@ -17,6 +17,7 @@ const BinaryElfSection = struct {
1717 elfOffset: u64,
1818 binaryOffset: u64,
1919 fileSize: usize,
20 name: ?[]const u8,
2021 segment: ?*BinaryElfSegment,
2122};
2223
......@@ -30,23 +31,55 @@ const BinaryElfSegment = struct {
3031};
3132
3233const BinaryElfOutput = struct {
33 segments: ArrayList(*BinaryElfSegment),
34 sections: ArrayList(*BinaryElfSection),
34 segments: ArrayListUnmanaged(*BinaryElfSegment),
35 sections: ArrayListUnmanaged(*BinaryElfSection),
36 allocator: Allocator,
37 shstrtab: ?[]const u8,
3538
3639 const Self = @This();
3740
3841 pub fn deinit(self: *Self) void {
39 self.sections.deinit();
40 self.segments.deinit();
42 if (self.shstrtab) |shstrtab|
43 self.allocator.free(shstrtab);
44 self.sections.deinit(self.allocator);
45 self.segments.deinit(self.allocator);
4146 }
4247
4348 pub fn parse(allocator: Allocator, elf_file: File) !Self {
4449 var self: Self = .{
45 .segments = ArrayList(*BinaryElfSegment).init(allocator),
46 .sections = ArrayList(*BinaryElfSection).init(allocator),
50 .segments = .{},
51 .sections = .{},
52 .allocator = allocator,
53 .shstrtab = null,
4754 };
55 errdefer self.sections.deinit(allocator);
56 errdefer self.segments.deinit(allocator);
57
4858 const elf_hdr = try std.elf.Header.read(&elf_file);
4959
60 self.shstrtab = blk: {
61 if (elf_hdr.shstrndx >= elf_hdr.shnum) break :blk null;
62
63 var section_headers = elf_hdr.section_header_iterator(&elf_file);
64
65 var section_counter: usize = 0;
66 while (section_counter < elf_hdr.shstrndx) : (section_counter += 1) {
67 _ = (try section_headers.next()).?;
68 }
69
70 const shstrtab_shdr = (try section_headers.next()).?;
71
72 const buffer = try allocator.alloc(u8, shstrtab_shdr.sh_size);
73 errdefer allocator.free(buffer);
74
75 const num_read = try elf_file.preadAll(buffer, shstrtab_shdr.sh_offset);
76 if (num_read != buffer.len) return error.EndOfStream;
77
78 break :blk buffer;
79 };
80
81 errdefer if (self.shstrtab) |shstrtab| allocator.free(shstrtab);
82
5083 var section_headers = elf_hdr.section_header_iterator(&elf_file);
5184 while (try section_headers.next()) |section| {
5285 if (sectionValidForOutput(section)) {
......@@ -57,7 +90,12 @@ const BinaryElfOutput = struct {
5790 newSection.fileSize = @intCast(usize, section.sh_size);
5891 newSection.segment = null;
5992
60 try self.sections.append(newSection);
93 newSection.name = if (self.shstrtab) |shstrtab|
94 std.mem.span(@ptrCast([*:0]const u8, &shstrtab[section.sh_name]))
95 else
96 null;
97
98 try self.sections.append(allocator, newSection);
6199 }
62100 }
63101
......@@ -89,7 +127,7 @@ const BinaryElfOutput = struct {
89127 }
90128 }
91129
92 try self.segments.append(newSegment);
130 try self.segments.append(allocator, newSegment);
93131 }
94132 }
95133
......@@ -150,8 +188,6 @@ const BinaryElfOutput = struct {
150188};
151189
152190fn writeBinaryElfSection(elf_file: File, out_file: File, section: *BinaryElfSection) !void {
153 try out_file.seekTo(section.binaryOffset);
154
155191 try out_file.writeFileAll(elf_file, .{
156192 .in_offset = section.elfOffset,
157193 .in_len = section.fileSize,
......@@ -298,7 +334,20 @@ fn containsValidAddressRange(segments: []*BinaryElfSegment) bool {
298334 return true;
299335}
300336
301fn emitRaw(allocator: Allocator, elf_path: []const u8, raw_path: []const u8, format: RawFormat) !void {
337fn padFile(f: fs.File, size: ?usize) !void {
338 if (size) |pad_size| {
339 const current_size = try f.getEndPos();
340 if (current_size < pad_size) {
341 try f.seekTo(pad_size - 1);
342 try f.writer().writeByte(0);
343 }
344 if (current_size > pad_size) {
345 return error.FileTooLarge; // Maybe this shouldn't be an error?
346 }
347 }
348}
349
350fn emitRaw(allocator: Allocator, elf_path: []const u8, raw_path: []const u8, options: CreateOptions) !void {
302351 var elf_file = try fs.cwd().openFile(elf_path, .{});
303352 defer elf_file.close();
304353
......@@ -308,11 +357,38 @@ fn emitRaw(allocator: Allocator, elf_path: []const u8, raw_path: []const u8, for
308357 var binary_elf_output = try BinaryElfOutput.parse(allocator, elf_file);
309358 defer binary_elf_output.deinit();
310359
311 switch (format) {
360 const effective_format = options.format orelse detectFormat(raw_path);
361
362 if (options.only_section_name) |target_name| {
363 switch (effective_format) {
364 // Hex format can only write segments/phdrs, sections not supported yet
365 .hex => return error.NotYetImplemented,
366 .bin => {
367 for (binary_elf_output.sections.items) |section| {
368 if (section.name) |curr_name| {
369 if (!std.mem.eql(u8, curr_name, target_name))
370 continue;
371 } else {
372 continue;
373 }
374
375 try writeBinaryElfSection(elf_file, out_file, section);
376 try padFile(out_file, options.pad_to_size);
377 return;
378 }
379 },
380 }
381
382 return error.SectionNotFound;
383 }
384
385 switch (effective_format) {
312386 .bin => {
313387 for (binary_elf_output.sections.items) |section| {
388 try out_file.seekTo(section.binaryOffset);
314389 try writeBinaryElfSection(elf_file, out_file, section);
315390 }
391 try padFile(out_file, options.pad_to_size);
316392 },
317393 .hex => {
318394 if (binary_elf_output.segments.items.len == 0) return;
......@@ -326,6 +402,10 @@ fn emitRaw(allocator: Allocator, elf_path: []const u8, raw_path: []const u8, for
326402 try hex_writer.writeSegment(segment, elf_file);
327403 }
328404 }
405 if (options.pad_to_size) |_| {
406 // Padding to a size in hex files isn't applicable
407 return error.InvalidArgument;
408 }
329409 try hex_writer.writeEOF();
330410 },
331411 }
......@@ -345,7 +425,7 @@ builder: *Builder,
345425artifact: *LibExeObjStep,
346426dest_dir: InstallDir,
347427dest_filename: []const u8,
348format: RawFormat,
428options: CreateOptions,
349429output_file: std.build.GeneratedFile,
350430
351431fn detectFormat(filename: []const u8) RawFormat {
......@@ -358,6 +438,8 @@ fn detectFormat(filename: []const u8) RawFormat {
358438pub const CreateOptions = struct {
359439 format: ?RawFormat = null,
360440 dest_dir: ?InstallDir = null,
441 only_section_name: ?[]const u8 = null,
442 pad_to_size: ?usize = null,
361443};
362444
363445pub fn create(builder: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8, options: CreateOptions) *InstallRawStep {
......@@ -373,7 +455,7 @@ pub fn create(builder: *Builder, artifact: *LibExeObjStep, dest_filename: []cons
373455 .lib => unreachable,
374456 },
375457 .dest_filename = dest_filename,
376 .format = if (options.format) |f| f else detectFormat(dest_filename),
458 .options = options,
377459 .output_file = std.build.GeneratedFile{ .step = &self.step },
378460 };
379461 self.step.dependOn(&artifact.step);
......@@ -399,7 +481,7 @@ fn make(step: *Step) !void {
399481 const full_dest_path = builder.getInstallPath(self.dest_dir, self.dest_filename);
400482
401483 fs.cwd().makePath(builder.getInstallPath(self.dest_dir, "")) catch unreachable;
402 try emitRaw(builder.allocator, full_src_path, full_dest_path, self.format);
484 try emitRaw(builder.allocator, full_src_path, full_dest_path, self.options);
403485 self.output_file.path = full_dest_path;
404486}
405487