mirror of
https://github.com/ziglang/zig.git
synced 2025-12-29 17:43:17 +00:00
Merge pull request #21591 from patrickwick/issue-19009
zig objcopy: support --add-section
This commit is contained in:
commit
cfd3bcffec
@ -40,6 +40,9 @@ fn cmdObjCopy(
|
||||
var only_keep_debug: bool = false;
|
||||
var compress_debug_sections: bool = false;
|
||||
var listen = false;
|
||||
var add_section: ?AddSection = null;
|
||||
var set_section_alignment: ?SetSectionAlignment = null;
|
||||
var set_section_flags: ?SetSectionFlags = null;
|
||||
while (i < args.len) : (i += 1) {
|
||||
const arg = args[i];
|
||||
if (!mem.startsWith(u8, arg, "-")) {
|
||||
@ -104,6 +107,37 @@ fn cmdObjCopy(
|
||||
i += 1;
|
||||
if (i >= args.len) fatal("expected another argument after '{s}'", .{arg});
|
||||
opt_extract = args[i];
|
||||
} else if (mem.eql(u8, arg, "--set-section-alignment")) {
|
||||
i += 1;
|
||||
if (i >= args.len) fatal("expected section name and alignment arguments after '{s}'", .{arg});
|
||||
|
||||
if (splitOption(args[i])) |split| {
|
||||
const alignment = std.fmt.parseInt(u32, split.second, 10) catch |err| {
|
||||
fatal("unable to parse alignment number: '{s}': {s}", .{ split.second, @errorName(err) });
|
||||
};
|
||||
if (!std.math.isPowerOfTwo(alignment)) fatal("alignment must be a power of two", .{});
|
||||
set_section_alignment = .{ .section_name = split.first, .alignment = alignment };
|
||||
} else {
|
||||
fatal("unrecognized argument: '{s}', expecting <name>=<alignment>", .{args[i]});
|
||||
}
|
||||
} else if (mem.eql(u8, arg, "--set-section-flags")) {
|
||||
i += 1;
|
||||
if (i >= args.len) fatal("expected section name and filename arguments after '{s}'", .{arg});
|
||||
|
||||
if (splitOption(args[i])) |split| {
|
||||
set_section_flags = .{ .section_name = split.first, .flags = parseSectionFlags(split.second) };
|
||||
} else {
|
||||
fatal("unrecognized argument: '{s}', expecting <name>=<flags>", .{args[i]});
|
||||
}
|
||||
} else if (mem.eql(u8, arg, "--add-section")) {
|
||||
i += 1;
|
||||
if (i >= args.len) fatal("expected section name and filename arguments after '{s}'", .{arg});
|
||||
|
||||
if (splitOption(args[i])) |split| {
|
||||
add_section = .{ .section_name = split.first, .file_path = split.second };
|
||||
} else {
|
||||
fatal("unrecognized argument: '{s}', expecting <name>=<file>", .{args[i]});
|
||||
}
|
||||
} else {
|
||||
fatal("unrecognized argument: '{s}'", .{arg});
|
||||
}
|
||||
@ -151,6 +185,12 @@ fn cmdObjCopy(
|
||||
fatal("zig objcopy: ELF to RAW or HEX copying does not support --strip", .{});
|
||||
if (opt_extract != null)
|
||||
fatal("zig objcopy: ELF to RAW or HEX copying does not support --extract-to", .{});
|
||||
if (add_section != null)
|
||||
fatal("zig objcopy: ELF to RAW or HEX copying does not support --add-section", .{});
|
||||
if (set_section_alignment != null)
|
||||
fatal("zig objcopy: ELF to RAW or HEX copying does not support --set_section_alignment", .{});
|
||||
if (set_section_flags != null)
|
||||
fatal("zig objcopy: ELF to RAW or HEX copying does not support --set_section_flags", .{});
|
||||
|
||||
try emitElf(arena, in_file, out_file, elf_hdr, .{
|
||||
.ofmt = out_fmt,
|
||||
@ -175,6 +215,9 @@ fn cmdObjCopy(
|
||||
.add_debuglink = opt_add_debuglink,
|
||||
.extract_to = opt_extract,
|
||||
.compress_debug = compress_debug_sections,
|
||||
.add_section = add_section,
|
||||
.set_section_alignment = set_section_alignment,
|
||||
.set_section_flags = set_section_flags,
|
||||
});
|
||||
return std.process.cleanExit();
|
||||
},
|
||||
@ -217,18 +260,21 @@ const usage =
|
||||
\\Usage: zig objcopy [options] input output
|
||||
\\
|
||||
\\Options:
|
||||
\\ -h, --help Print this help and exit
|
||||
\\ --output-target=<value> Format of the output file
|
||||
\\ -O <value> Alias for --output-target
|
||||
\\ --only-section=<section> Remove all but <section>
|
||||
\\ -j <value> Alias for --only-section
|
||||
\\ --pad-to <addr> Pad the last section up to address <addr>
|
||||
\\ --strip-debug, -g Remove all debug sections from the output.
|
||||
\\ --strip-all, -S Remove all debug sections and symbol table from the output.
|
||||
\\ --only-keep-debug Strip a file, removing contents of any sections that would not be stripped by --strip-debug and leaving the debugging sections intact.
|
||||
\\ --add-gnu-debuglink=<file> Creates a .gnu_debuglink section which contains a reference to <file> and adds it to the output file.
|
||||
\\ --extract-to <file> Extract the removed sections into <file>, and add a .gnu-debuglink section.
|
||||
\\ --compress-debug-sections Compress DWARF debug sections with zlib
|
||||
\\ -h, --help Print this help and exit
|
||||
\\ --output-target=<value> Format of the output file
|
||||
\\ -O <value> Alias for --output-target
|
||||
\\ --only-section=<section> Remove all but <section>
|
||||
\\ -j <value> Alias for --only-section
|
||||
\\ --pad-to <addr> Pad the last section up to address <addr>
|
||||
\\ --strip-debug, -g Remove all debug sections from the output.
|
||||
\\ --strip-all, -S Remove all debug sections and symbol table from the output.
|
||||
\\ --only-keep-debug Strip a file, removing contents of any sections that would not be stripped by --strip-debug and leaving the debugging sections intact.
|
||||
\\ --add-gnu-debuglink=<file> Creates a .gnu_debuglink section which contains a reference to <file> and adds it to the output file.
|
||||
\\ --extract-to <file> Extract the removed sections into <file>, and add a .gnu-debuglink section.
|
||||
\\ --compress-debug-sections Compress DWARF debug sections with zlib
|
||||
\\ --set-section-alignment <name>=<align> Set alignment of section <name> to <align> bytes. Must be a power of two.
|
||||
\\ --set-section-flags <name>=<file> Set flags of section <name> to <flags> represented as a comma separated set of flags.
|
||||
\\ --add-section <name>=<file> Add file content from <file> with the a new section named <name>.
|
||||
\\
|
||||
;
|
||||
|
||||
@ -236,6 +282,24 @@ pub const EmitRawElfOptions = struct {
|
||||
ofmt: std.Target.ObjectFormat,
|
||||
only_section: ?[]const u8 = null,
|
||||
pad_to: ?u64 = null,
|
||||
add_section: ?AddSection = null,
|
||||
set_section_alignment: ?SetSectionAlignment = null,
|
||||
set_section_flags: ?SetSectionFlags = null,
|
||||
};
|
||||
|
||||
const AddSection = struct {
|
||||
section_name: []const u8,
|
||||
file_path: []const u8,
|
||||
};
|
||||
|
||||
const SetSectionAlignment = struct {
|
||||
section_name: []const u8,
|
||||
alignment: u32,
|
||||
};
|
||||
|
||||
const SetSectionFlags = struct {
|
||||
section_name: []const u8,
|
||||
flags: SectionFlags,
|
||||
};
|
||||
|
||||
fn emitElf(
|
||||
@ -678,6 +742,9 @@ const StripElfOptions = struct {
|
||||
strip_debug: bool = false,
|
||||
only_keep_debug: bool = false,
|
||||
compress_debug: bool = false,
|
||||
add_section: ?AddSection,
|
||||
set_section_alignment: ?SetSectionAlignment,
|
||||
set_section_flags: ?SetSectionFlags,
|
||||
};
|
||||
|
||||
fn stripElf(
|
||||
@ -721,6 +788,14 @@ fn stripElf(
|
||||
var elf_file = try ElfFile(is_64).parse(allocator, in_file, elf_hdr);
|
||||
defer elf_file.deinit();
|
||||
|
||||
if (options.add_section) |user_section| {
|
||||
for (elf_file.sections) |section| {
|
||||
if (std.mem.eql(u8, section.name, user_section.section_name)) {
|
||||
fatal("zig objcopy: unable to add section '{s}'. Section already exists in input", .{user_section.section_name});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (filter_complement) |flt| {
|
||||
// write the .dbg file and close it, so it can be read back to compute the debuglink checksum.
|
||||
const path = options.extract_to.?;
|
||||
@ -733,7 +808,14 @@ fn stripElf(
|
||||
}
|
||||
|
||||
const debuglink: ?DebugLink = if (debuglink_path) |path| ElfFileHelper.createDebugLink(path) else null;
|
||||
try elf_file.emit(allocator, out_file, in_file, .{ .section_filter = filter, .debuglink = debuglink, .compress_debug = options.compress_debug });
|
||||
try elf_file.emit(allocator, out_file, in_file, .{
|
||||
.section_filter = filter,
|
||||
.debuglink = debuglink,
|
||||
.compress_debug = options.compress_debug,
|
||||
.add_section = options.add_section,
|
||||
.set_section_alignment = options.set_section_alignment,
|
||||
.set_section_flags = options.set_section_flags,
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -786,7 +868,7 @@ fn ElfFile(comptime is_64: bool) type {
|
||||
// program header: list of segments
|
||||
const program_segments = blk: {
|
||||
if (@sizeOf(Elf_Phdr) != header.phentsize)
|
||||
fatal("zig objcopy: unsuported ELF file, unexpected phentsize ({d})", .{header.phentsize});
|
||||
fatal("zig objcopy: unsupported ELF file, unexpected phentsize ({d})", .{header.phentsize});
|
||||
|
||||
const program_header = try allocator.alloc(Elf_Phdr, header.phnum);
|
||||
const bytes_read = try in_file.preadAll(std.mem.sliceAsBytes(program_header), header.phoff);
|
||||
@ -798,7 +880,7 @@ fn ElfFile(comptime is_64: bool) type {
|
||||
// section header
|
||||
const sections = blk: {
|
||||
if (@sizeOf(Elf_Shdr) != header.shentsize)
|
||||
fatal("zig objcopy: unsuported ELF file, unexpected shentsize ({d})", .{header.shentsize});
|
||||
fatal("zig objcopy: unsupported ELF file, unexpected shentsize ({d})", .{header.shentsize});
|
||||
|
||||
const section_header = try allocator.alloc(Section, header.shnum);
|
||||
|
||||
@ -896,6 +978,9 @@ fn ElfFile(comptime is_64: bool) type {
|
||||
section_filter: Filter = .all,
|
||||
debuglink: ?DebugLink = null,
|
||||
compress_debug: bool = false,
|
||||
add_section: ?AddSection = null,
|
||||
set_section_alignment: ?SetSectionAlignment = null,
|
||||
set_section_flags: ?SetSectionFlags = null,
|
||||
};
|
||||
fn emit(self: *const Self, gpa: Allocator, out_file: File, in_file: File, options: EmitElfOptions) !void {
|
||||
var arena = std.heap.ArenaAllocator.init(gpa);
|
||||
@ -934,6 +1019,10 @@ fn ElfFile(comptime is_64: bool) type {
|
||||
if (options.debuglink != null)
|
||||
next_idx += 1;
|
||||
|
||||
if (options.add_section != null) {
|
||||
next_idx += 1;
|
||||
}
|
||||
|
||||
break :blk next_idx;
|
||||
};
|
||||
|
||||
@ -959,6 +1048,28 @@ fn ElfFile(comptime is_64: bool) type {
|
||||
break :blk new_offset;
|
||||
};
|
||||
|
||||
// add user section to the string table if needed
|
||||
const user_section_name: u32 = blk: {
|
||||
if (options.add_section == null) break :blk elf.SHN_UNDEF;
|
||||
if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF)
|
||||
fatal("zig objcopy: no strtab, cannot add the user section", .{}); // TODO add the section if needed?
|
||||
|
||||
const strtab = &self.sections[self.raw_elf_header.e_shstrndx];
|
||||
const update = §ions_update[self.raw_elf_header.e_shstrndx];
|
||||
|
||||
const name = options.add_section.?.section_name;
|
||||
const new_offset: u32 = @intCast(strtab.payload.?.len);
|
||||
const buf = try allocator.alignedAlloc(u8, section_memory_align, new_offset + name.len + 1);
|
||||
@memcpy(buf[0..new_offset], strtab.payload.?);
|
||||
@memcpy(buf[new_offset..][0..name.len], name);
|
||||
buf[new_offset + name.len] = 0;
|
||||
|
||||
assert(update.action == .keep);
|
||||
update.payload = buf;
|
||||
|
||||
break :blk new_offset;
|
||||
};
|
||||
|
||||
// maybe compress .debug sections
|
||||
if (options.compress_debug) {
|
||||
for (self.sections[1..], sections_update[1..]) |section, *update| {
|
||||
@ -1018,7 +1129,7 @@ fn ElfFile(comptime is_64: bool) type {
|
||||
if (section.section.sh_type == elf.SHT_NOBITS)
|
||||
continue;
|
||||
if (section.section.sh_offset < offset) {
|
||||
fatal("zig objcopy: unsuported ELF file", .{});
|
||||
fatal("zig objcopy: unsupported ELF file", .{});
|
||||
}
|
||||
offset = section.section.sh_offset;
|
||||
}
|
||||
@ -1134,10 +1245,100 @@ fn ElfFile(comptime is_64: bool) type {
|
||||
eof_offset += @as(Elf_OffSize, @intCast(payload.len));
|
||||
}
|
||||
|
||||
// --add-section
|
||||
if (options.add_section) |add_section| {
|
||||
var section_file = fs.cwd().openFile(add_section.file_path, .{}) catch |err|
|
||||
fatal("unable to open '{s}': {s}", .{ add_section.file_path, @errorName(err) });
|
||||
defer section_file.close();
|
||||
|
||||
const payload = try section_file.readToEndAlloc(arena.allocator(), std.math.maxInt(usize));
|
||||
|
||||
dest_sections[dest_section_idx] = Elf_Shdr{
|
||||
.sh_name = user_section_name,
|
||||
.sh_type = elf.SHT_PROGBITS,
|
||||
.sh_flags = 0,
|
||||
.sh_addr = 0,
|
||||
.sh_offset = eof_offset,
|
||||
.sh_size = @intCast(payload.len),
|
||||
.sh_link = elf.SHN_UNDEF,
|
||||
.sh_info = elf.SHN_UNDEF,
|
||||
.sh_addralign = 4,
|
||||
.sh_entsize = 0,
|
||||
};
|
||||
dest_section_idx += 1;
|
||||
|
||||
cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = payload, .out_offset = eof_offset } });
|
||||
eof_offset += @as(Elf_OffSize, @intCast(payload.len));
|
||||
}
|
||||
|
||||
assert(dest_section_idx == new_shnum);
|
||||
break :blk dest_sections;
|
||||
};
|
||||
|
||||
// --set-section-alignment: overwrite alignment
|
||||
if (options.set_section_alignment) |set_align| {
|
||||
if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF)
|
||||
fatal("zig objcopy: no strtab, cannot add the user section", .{}); // TODO add the section if needed?
|
||||
|
||||
const strtab = §ions_update[self.raw_elf_header.e_shstrndx];
|
||||
for (updated_section_header) |*section| {
|
||||
const section_name = std.mem.span(@as([*:0]const u8, @ptrCast(&strtab.payload.?[section.sh_name])));
|
||||
if (std.mem.eql(u8, section_name, set_align.section_name)) {
|
||||
section.sh_addralign = set_align.alignment;
|
||||
break;
|
||||
}
|
||||
} else std.log.warn("Skipping --set-section-alignment. Section '{s}' not found", .{set_align.section_name});
|
||||
}
|
||||
|
||||
// --set-section-flags: overwrite flags
|
||||
if (options.set_section_flags) |set_flags| {
|
||||
if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF)
|
||||
fatal("zig objcopy: no strtab, cannot add the user section", .{}); // TODO add the section if needed?
|
||||
|
||||
const strtab = §ions_update[self.raw_elf_header.e_shstrndx];
|
||||
for (updated_section_header) |*section| {
|
||||
const section_name = std.mem.span(@as([*:0]const u8, @ptrCast(&strtab.payload.?[section.sh_name])));
|
||||
if (std.mem.eql(u8, section_name, set_flags.section_name)) {
|
||||
section.sh_flags = std.elf.SHF_WRITE; // default is writable cleared by "readonly"
|
||||
const f = set_flags.flags;
|
||||
|
||||
// Supporting a subset of GNU and LLVM objcopy for ELF only
|
||||
// GNU:
|
||||
// alloc: add SHF_ALLOC
|
||||
// contents: if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing
|
||||
// load: if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing (same as contents)
|
||||
// noload: not ELF relevant
|
||||
// readonly: clear default SHF_WRITE flag
|
||||
// code: add SHF_EXECINSTR
|
||||
// data: not ELF relevant
|
||||
// rom: ignored
|
||||
// exclude: add SHF_EXCLUDE
|
||||
// share: not ELF relevant
|
||||
// debug: not ELF relevant
|
||||
// large: add SHF_X86_64_LARGE. Fatal error if target is not x86_64
|
||||
if (f.alloc) section.sh_flags |= std.elf.SHF_ALLOC;
|
||||
if (f.contents or f.load) {
|
||||
if (section.sh_type == std.elf.SHT_NOBITS) section.sh_type = std.elf.SHT_PROGBITS;
|
||||
}
|
||||
if (f.readonly) section.sh_flags &= ~@as(@TypeOf(section.sh_type), std.elf.SHF_WRITE);
|
||||
if (f.code) section.sh_flags |= std.elf.SHF_EXECINSTR;
|
||||
if (f.exclude) section.sh_flags |= std.elf.SHF_EXCLUDE;
|
||||
if (f.large) {
|
||||
if (updated_elf_header.e_machine != std.elf.EM.X86_64)
|
||||
fatal("zig objcopy: 'large' section flag is only supported on x86_64 targets", .{});
|
||||
section.sh_flags |= std.elf.SHF_X86_64_LARGE;
|
||||
}
|
||||
|
||||
// LLVM:
|
||||
// merge: add SHF_MERGE
|
||||
// strings: add SHF_STRINGS
|
||||
if (f.merge) section.sh_flags |= std.elf.SHF_MERGE;
|
||||
if (f.strings) section.sh_flags |= std.elf.SHF_STRINGS;
|
||||
break;
|
||||
}
|
||||
} else std.log.warn("Skipping --set-section-flags. Section '{s}' not found", .{set_flags.section_name});
|
||||
}
|
||||
|
||||
// write the section header at the tail
|
||||
{
|
||||
const offset = std.mem.alignForward(Elf_OffSize, eof_offset, @alignOf(Elf_Shdr));
|
||||
@ -1361,3 +1562,111 @@ const ElfFileHelper = struct {
|
||||
return hasher.final();
|
||||
}
|
||||
};
|
||||
|
||||
const SectionFlags = packed struct {
|
||||
alloc: bool = false,
|
||||
contents: bool = false,
|
||||
load: bool = false,
|
||||
noload: bool = false,
|
||||
readonly: bool = false,
|
||||
code: bool = false,
|
||||
data: bool = false,
|
||||
rom: bool = false,
|
||||
exclude: bool = false,
|
||||
shared: bool = false,
|
||||
debug: bool = false,
|
||||
large: bool = false,
|
||||
merge: bool = false,
|
||||
strings: bool = false,
|
||||
};
|
||||
|
||||
fn parseSectionFlags(comma_separated_flags: []const u8) SectionFlags {
|
||||
const P = struct {
|
||||
fn parse(flags: *SectionFlags, string: []const u8) void {
|
||||
if (string.len == 0) return;
|
||||
|
||||
if (std.mem.eql(u8, string, "alloc")) {
|
||||
flags.alloc = true;
|
||||
} else if (std.mem.eql(u8, string, "contents")) {
|
||||
flags.contents = true;
|
||||
} else if (std.mem.eql(u8, string, "load")) {
|
||||
flags.load = true;
|
||||
} else if (std.mem.eql(u8, string, "noload")) {
|
||||
flags.noload = true;
|
||||
} else if (std.mem.eql(u8, string, "readonly")) {
|
||||
flags.readonly = true;
|
||||
} else if (std.mem.eql(u8, string, "code")) {
|
||||
flags.code = true;
|
||||
} else if (std.mem.eql(u8, string, "data")) {
|
||||
flags.data = true;
|
||||
} else if (std.mem.eql(u8, string, "rom")) {
|
||||
flags.rom = true;
|
||||
} else if (std.mem.eql(u8, string, "exclude")) {
|
||||
flags.exclude = true;
|
||||
} else if (std.mem.eql(u8, string, "shared")) {
|
||||
flags.shared = true;
|
||||
} else if (std.mem.eql(u8, string, "debug")) {
|
||||
flags.debug = true;
|
||||
} else if (std.mem.eql(u8, string, "large")) {
|
||||
flags.large = true;
|
||||
} else if (std.mem.eql(u8, string, "merge")) {
|
||||
flags.merge = true;
|
||||
} else if (std.mem.eql(u8, string, "strings")) {
|
||||
flags.strings = true;
|
||||
} else {
|
||||
std.log.warn("Skipping unrecognized section flag '{s}'", .{string});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var flags = SectionFlags{};
|
||||
var offset: usize = 0;
|
||||
for (comma_separated_flags, 0..) |c, i| {
|
||||
if (c == ',') {
|
||||
defer offset = i + 1;
|
||||
const string = comma_separated_flags[offset..i];
|
||||
P.parse(&flags, string);
|
||||
}
|
||||
}
|
||||
P.parse(&flags, comma_separated_flags[offset..]);
|
||||
return flags;
|
||||
}
|
||||
|
||||
test "Parse section flags" {
|
||||
const F = SectionFlags;
|
||||
try std.testing.expectEqual(F{}, parseSectionFlags(""));
|
||||
try std.testing.expectEqual(F{}, parseSectionFlags(","));
|
||||
try std.testing.expectEqual(F{}, parseSectionFlags("abc"));
|
||||
try std.testing.expectEqual(F{ .alloc = true }, parseSectionFlags("alloc"));
|
||||
try std.testing.expectEqual(F{ .data = true }, parseSectionFlags("data,"));
|
||||
try std.testing.expectEqual(F{ .alloc = true, .code = true }, parseSectionFlags("alloc,code"));
|
||||
try std.testing.expectEqual(F{ .alloc = true, .code = true }, parseSectionFlags("alloc,code,not_supported"));
|
||||
}
|
||||
|
||||
const SplitResult = struct { first: []const u8, second: []const u8 };
|
||||
|
||||
fn splitOption(option: []const u8) ?SplitResult {
|
||||
const separator = '=';
|
||||
if (option.len < 3) return null; // minimum "a=b"
|
||||
for (1..option.len - 1) |i| {
|
||||
if (option[i] == separator) return .{
|
||||
.first = option[0..i],
|
||||
.second = option[i + 1 ..],
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
test "Split option" {
|
||||
{
|
||||
const split = splitOption(".abc=123");
|
||||
try std.testing.expect(split != null);
|
||||
try std.testing.expectEqualStrings(".abc", split.?.first);
|
||||
try std.testing.expectEqualStrings("123", split.?.second);
|
||||
}
|
||||
|
||||
try std.testing.expectEqual(null, splitOption(""));
|
||||
try std.testing.expectEqual(null, splitOption("=abc"));
|
||||
try std.testing.expectEqual(null, splitOption("abc="));
|
||||
try std.testing.expectEqual(null, splitOption("abc"));
|
||||
}
|
||||
|
||||
@ -26,6 +26,50 @@ pub const Strip = enum {
|
||||
debug_and_symbols,
|
||||
};
|
||||
|
||||
pub const SectionFlags = packed struct {
|
||||
/// add SHF_ALLOC
|
||||
alloc: bool = false,
|
||||
|
||||
/// if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing
|
||||
contents: bool = false,
|
||||
|
||||
/// if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing (same as contents)
|
||||
load: bool = false,
|
||||
|
||||
/// readonly: clear default SHF_WRITE flag
|
||||
readonly: bool = false,
|
||||
|
||||
/// add SHF_EXECINSTR
|
||||
code: bool = false,
|
||||
|
||||
/// add SHF_EXCLUDE
|
||||
exclude: bool = false,
|
||||
|
||||
/// add SHF_X86_64_LARGE. Fatal error if target is not x86_64
|
||||
large: bool = false,
|
||||
|
||||
/// add SHF_MERGE
|
||||
merge: bool = false,
|
||||
|
||||
/// add SHF_STRINGS
|
||||
strings: bool = false,
|
||||
};
|
||||
|
||||
pub const AddSection = struct {
|
||||
section_name: []const u8,
|
||||
file_path: std.Build.LazyPath,
|
||||
};
|
||||
|
||||
pub const SetSectionAlignment = struct {
|
||||
section_name: []const u8,
|
||||
alignment: u32,
|
||||
};
|
||||
|
||||
pub const SetSectionFlags = struct {
|
||||
section_name: []const u8,
|
||||
flags: SectionFlags,
|
||||
};
|
||||
|
||||
step: Step,
|
||||
input_file: std.Build.LazyPath,
|
||||
basename: []const u8,
|
||||
@ -38,6 +82,10 @@ pad_to: ?u64,
|
||||
strip: Strip,
|
||||
compress_debug: bool,
|
||||
|
||||
add_section: ?AddSection,
|
||||
set_section_alignment: ?SetSectionAlignment,
|
||||
set_section_flags: ?SetSectionFlags,
|
||||
|
||||
pub const Options = struct {
|
||||
basename: ?[]const u8 = null,
|
||||
format: ?RawFormat = null,
|
||||
@ -51,6 +99,10 @@ pub const Options = struct {
|
||||
/// note: the `basename` is baked into the elf file to specify the link to the separate debug file.
|
||||
/// see https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
|
||||
extract_to_separate_file: bool = false,
|
||||
|
||||
add_section: ?AddSection = null,
|
||||
set_section_alignment: ?SetSectionAlignment = null,
|
||||
set_section_flags: ?SetSectionFlags = null,
|
||||
};
|
||||
|
||||
pub fn create(
|
||||
@ -75,6 +127,9 @@ pub fn create(
|
||||
.pad_to = options.pad_to,
|
||||
.strip = options.strip,
|
||||
.compress_debug = options.compress_debug,
|
||||
.add_section = options.add_section,
|
||||
.set_section_alignment = options.set_section_alignment,
|
||||
.set_section_flags = options.set_section_flags,
|
||||
};
|
||||
input_file.addStepDependencies(&objcopy.step);
|
||||
return objcopy;
|
||||
@ -155,6 +210,31 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
|
||||
if (objcopy.output_file_debug != null) {
|
||||
try argv.appendSlice(&.{b.fmt("--extract-to={s}", .{full_dest_path_debug})});
|
||||
}
|
||||
if (objcopy.add_section) |section| {
|
||||
try argv.append("--add-section");
|
||||
try argv.appendSlice(&.{b.fmt("{s}={s}", .{ section.section_name, section.file_path.getPath(b) })});
|
||||
}
|
||||
if (objcopy.set_section_alignment) |set_align| {
|
||||
try argv.append("--set-section-alignment");
|
||||
try argv.appendSlice(&.{b.fmt("{s}={d}", .{ set_align.section_name, set_align.alignment })});
|
||||
}
|
||||
if (objcopy.set_section_flags) |set_flags| {
|
||||
const f = set_flags.flags;
|
||||
// trailing comma is allowed
|
||||
try argv.append("--set-section-flags");
|
||||
try argv.appendSlice(&.{b.fmt("{s}={s}{s}{s}{s}{s}{s}{s}{s}{s}", .{
|
||||
set_flags.section_name,
|
||||
if (f.alloc) "alloc," else "",
|
||||
if (f.contents) "contents," else "",
|
||||
if (f.load) "load," else "",
|
||||
if (f.readonly) "readonly," else "",
|
||||
if (f.code) "code," else "",
|
||||
if (f.exclude) "exclude," else "",
|
||||
if (f.large) "large," else "",
|
||||
if (f.merge) "merge," else "",
|
||||
if (f.strings) "strings," else "",
|
||||
})});
|
||||
}
|
||||
|
||||
try argv.appendSlice(&.{ full_src_path, full_dest_path });
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user