feature. See also
. The project being documented here (as the example) is the Zig library itself.
objcopy.BinaryElfOutput
const BinaryElfOutput = struct
File
Code
const BinaryElfOutput = struct {
segments: std.ArrayList(*BinaryElfSegment),
sections: std.ArrayList(*BinaryElfSection),
allocator: Allocator,
shstrtab: ?[]const u8,
const Self = @This();
pub fn deinit(self: *Self) void {
if (self.shstrtab) |shstrtab|
self.allocator.free(shstrtab);
self.sections.deinit(self.allocator);
self.segments.deinit(self.allocator);
}
pub fn parse(allocator: Allocator, in: *File.Reader, elf_hdr: elf.Header) !Self {
var self: Self = .{
.segments = .empty,
.sections = .empty,
.allocator = allocator,
.shstrtab = null,
};
errdefer self.sections.deinit(allocator);
errdefer self.segments.deinit(allocator);
self.shstrtab = blk: {
if (elf_hdr.shstrndx >= elf_hdr.shnum) break :blk null;
var section_headers = elf_hdr.iterateSectionHeaders(in);
var section_counter: usize = 0;
while (section_counter < elf_hdr.shstrndx) : (section_counter += 1) {
_ = (try section_headers.next()).?;
}
const shstrtab_shdr = (try section_headers.next()).?;
try in.seekTo(shstrtab_shdr.sh_offset);
break :blk try in.interface.readAlloc(allocator, shstrtab_shdr.sh_size);
};
errdefer if (self.shstrtab) |shstrtab| allocator.free(shstrtab);
var section_headers = elf_hdr.iterateSectionHeaders(in);
while (try section_headers.next()) |section| {
if (sectionValidForOutput(section)) {
const newSection = try allocator.create(BinaryElfSection);
newSection.binaryOffset = 0;
newSection.elfOffset = section.sh_offset;
newSection.fileSize = @intCast(section.sh_size);
newSection.segment = null;
newSection.name = if (self.shstrtab) |shstrtab|
std.mem.span(@as([*:0]const u8, @ptrCast(&shstrtab[section.sh_name])))
else
null;
try self.sections.append(allocator, newSection);
}
}
var program_headers = elf_hdr.iterateProgramHeaders(in);
while (try program_headers.next()) |phdr| {
if (phdr.p_type == elf.PT_LOAD) {
const newSegment = try allocator.create(BinaryElfSegment);
newSegment.physicalAddress = phdr.p_paddr;
newSegment.virtualAddress = phdr.p_vaddr;
newSegment.fileSize = @intCast(phdr.p_filesz);
newSegment.elfOffset = phdr.p_offset;
newSegment.binaryOffset = 0;
newSegment.firstSection = null;
for (self.sections.items) |section| {
if (sectionWithinSegment(section, phdr)) {
if (section.segment) |sectionSegment| {
if (sectionSegment.elfOffset > newSegment.elfOffset) {
section.segment = newSegment;
}
} else {
section.segment = newSegment;
}
if (newSegment.firstSection == null) {
newSegment.firstSection = section;
}
}
}
try self.segments.append(allocator, newSegment);
}
}
mem.sort(*BinaryElfSegment, self.segments.items, {}, segmentSortCompare);
for (self.segments.items, 0..) |firstSegment, i| {
if (firstSegment.firstSection) |firstSection| {
const diff = firstSection.elfOffset - firstSegment.elfOffset;
firstSegment.elfOffset += diff;
firstSegment.fileSize += diff;
firstSegment.physicalAddress += diff;
const basePhysicalAddress = firstSegment.physicalAddress;
for (self.segments.items[i + 1 ..]) |segment| {
segment.binaryOffset = segment.physicalAddress - basePhysicalAddress;
}
break;
}
}
for (self.sections.items) |section| {
if (section.segment) |segment| {
section.binaryOffset = segment.binaryOffset + (section.elfOffset - segment.elfOffset);
}
}
mem.sort(*BinaryElfSection, self.sections.items, {}, sectionSortCompare);
return self;
}
fn sectionWithinSegment(section: *BinaryElfSection, segment: elf.Elf64_Phdr) bool {
return segment.p_offset <= section.elfOffset and (segment.p_offset + segment.p_filesz) >= (section.elfOffset + section.fileSize);
}
fn sectionValidForOutput(shdr: anytype) bool {
return shdr.sh_type != elf.SHT_NOBITS and
((shdr.sh_flags & elf.SHF_ALLOC) == elf.SHF_ALLOC);
}
fn segmentSortCompare(context: void, left: *BinaryElfSegment, right: *BinaryElfSegment) bool {
_ = context;
if (left.physicalAddress < right.physicalAddress) {
return true;
}
if (left.physicalAddress > right.physicalAddress) {
return false;
}
return false;
}
fn sectionSortCompare(context: void, left: *BinaryElfSection, right: *BinaryElfSection) bool {
_ = context;
return left.binaryOffset < right.binaryOffset;
}
}