mirror of
https://github.com/ziglang/zig.git
synced 2024-11-27 23:52:31 +00:00
rework some old ELF parsing code and start to fix emitRaw
This commit is contained in:
parent
bd14a81e30
commit
ed13cffca4
@ -14,11 +14,6 @@ const io = std.io;
|
||||
const sort = std.sort;
|
||||
const warn = std.debug.warn;
|
||||
|
||||
const BinOutStream = io.OutStream(anyerror);
|
||||
const BinSeekStream = io.SeekableStream(anyerror, anyerror);
|
||||
const ElfSeekStream = io.SeekableStream(anyerror, anyerror);
|
||||
const ElfInStream = io.InStream(anyerror);
|
||||
|
||||
const BinaryElfSection = struct {
|
||||
elfOffset: u64,
|
||||
binaryOffset: u64,
|
||||
@ -41,22 +36,21 @@ const BinaryElfOutput = struct {
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn init(allocator: *Allocator) Self {
|
||||
return Self{
|
||||
.segments = ArrayList(*BinaryElfSegment).init(allocator),
|
||||
.sections = ArrayList(*BinaryElfSection).init(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.sections.deinit();
|
||||
self.segments.deinit();
|
||||
}
|
||||
|
||||
pub fn parseElf(self: *Self, elfFile: elf.Elf) !void {
|
||||
const allocator = self.segments.allocator;
|
||||
pub fn parse(allocator: *Allocator, elf_file: File) !Self {
|
||||
var self: Self = .{
|
||||
.segments = ArrayList(*BinaryElfSegment).init(allocator),
|
||||
.sections = ArrayList(*BinaryElfSection).init(allocator),
|
||||
};
|
||||
const elf_hdrs = try std.elf.readAllHeaders(allocator, elf_file);
|
||||
|
||||
for (elfFile.section_headers) |section, i| {
|
||||
var binaryElfOutput = BinaryElfOutput.init(arena_allocator);
|
||||
|
||||
for (elf_hdrs.section_headers) |section, i| {
|
||||
if (sectionValidForOutput(section)) {
|
||||
const newSection = try allocator.create(BinaryElfSection);
|
||||
|
||||
@ -69,19 +63,19 @@ const BinaryElfOutput = struct {
|
||||
}
|
||||
}
|
||||
|
||||
for (elfFile.program_headers) |programHeader, i| {
|
||||
if (programHeader.p_type == elf.PT_LOAD) {
|
||||
for (elf_hdrs.program_headers) |phdr, i| {
|
||||
if (phdr.p_type == elf.PT_LOAD) {
|
||||
const newSegment = try allocator.create(BinaryElfSegment);
|
||||
|
||||
newSegment.physicalAddress = if (programHeader.p_paddr != 0) programHeader.p_paddr else programHeader.p_vaddr;
|
||||
newSegment.virtualAddress = programHeader.p_vaddr;
|
||||
newSegment.fileSize = @intCast(usize, programHeader.p_filesz);
|
||||
newSegment.elfOffset = programHeader.p_offset;
|
||||
newSegment.physicalAddress = if (phdr.p_paddr != 0) phdr.p_paddr else phdr.p_vaddr;
|
||||
newSegment.virtualAddress = phdr.p_vaddr;
|
||||
newSegment.fileSize = @intCast(usize, phdr.p_filesz);
|
||||
newSegment.elfOffset = phdr.p_offset;
|
||||
newSegment.binaryOffset = 0;
|
||||
newSegment.firstSection = null;
|
||||
|
||||
for (self.sections.toSlice()) |section| {
|
||||
if (sectionWithinSegment(section, programHeader)) {
|
||||
if (sectionWithinSegment(section, phdr)) {
|
||||
if (section.segment) |sectionSegment| {
|
||||
if (sectionSegment.elfOffset > newSegment.elfOffset) {
|
||||
section.segment = newSegment;
|
||||
@ -126,14 +120,17 @@ const BinaryElfOutput = struct {
|
||||
}
|
||||
|
||||
sort.sort(*BinaryElfSection, self.sections.toSlice(), sectionSortCompare);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
fn sectionWithinSegment(section: *BinaryElfSection, segment: elf.ProgramHeader) bool {
|
||||
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(section: elf.SectionHeader) bool {
|
||||
return section.sh_size > 0 and section.sh_type != elf.SHT_NOBITS and ((section.sh_flags & elf.SHF_ALLOC) == elf.SHF_ALLOC);
|
||||
fn sectionValidForOutput(shdr: var) bool {
|
||||
return shdr.sh_size > 0 and shdr.sh_type != elf.SHT_NOBITS and
|
||||
((shdr.sh_flags & elf.SHF_ALLOC) == elf.SHF_ALLOC);
|
||||
}
|
||||
|
||||
fn segmentSortCompare(left: *BinaryElfSegment, right: *BinaryElfSegment) bool {
|
||||
@ -151,60 +148,27 @@ const BinaryElfOutput = struct {
|
||||
}
|
||||
};
|
||||
|
||||
const WriteContext = struct {
|
||||
inStream: *ElfInStream,
|
||||
inSeekStream: *ElfSeekStream,
|
||||
outStream: *BinOutStream,
|
||||
outSeekStream: *BinSeekStream,
|
||||
};
|
||||
fn writeBinaryElfSection(elf_file: File, out_file: File, section: *BinaryElfSection) !void {
|
||||
try out_file.seekTo(section.binaryOffset);
|
||||
|
||||
fn writeBinaryElfSection(allocator: *Allocator, context: WriteContext, section: *BinaryElfSection) !void {
|
||||
var readBuffer = try allocator.alloc(u8, section.fileSize);
|
||||
defer allocator.free(readBuffer);
|
||||
|
||||
try context.inSeekStream.seekTo(section.elfOffset);
|
||||
_ = try context.inStream.read(readBuffer);
|
||||
|
||||
try context.outSeekStream.seekTo(section.binaryOffset);
|
||||
try context.outStream.write(readBuffer);
|
||||
try out_file.writeFileAll(elf_file, .{
|
||||
.in_offset = section.elfOffset,
|
||||
.in_len = section.fileSize,
|
||||
});
|
||||
}
|
||||
|
||||
fn emit_raw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !void {
|
||||
var arenaAlloc = ArenaAllocator.init(allocator);
|
||||
errdefer arenaAlloc.deinit();
|
||||
var arena_allocator = &arenaAlloc.allocator;
|
||||
fn emitRaw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !void {
|
||||
var elf_file = try fs.cwd().openFile(elf_path, .{});
|
||||
defer elf_file.close();
|
||||
|
||||
const currentDir = fs.cwd();
|
||||
var out_file = try fs.cwd().createFile(raw_path, .{});
|
||||
defer out_file.close();
|
||||
|
||||
var file = try currentDir.openFile(elf_path, File.OpenFlags{});
|
||||
defer file.close();
|
||||
const binary_elf_output = BinaryElfOutput.parse(allocator, elf_file);
|
||||
defer binary_elf_output.deinit();
|
||||
|
||||
var fileInStream = file.inStream();
|
||||
var fileSeekStream = file.seekableStream();
|
||||
|
||||
var elfFile = try elf.Elf.openStream(allocator, @ptrCast(*ElfSeekStream, &fileSeekStream.stream), @ptrCast(*ElfInStream, &fileInStream.stream));
|
||||
defer elfFile.close();
|
||||
|
||||
var outFile = try currentDir.createFile(raw_path, File.CreateFlags{});
|
||||
defer outFile.close();
|
||||
|
||||
var outFileOutStream = outFile.outStream();
|
||||
var outFileSeekStream = outFile.seekableStream();
|
||||
|
||||
const writeContext = WriteContext{
|
||||
.inStream = @ptrCast(*ElfInStream, &fileInStream.stream),
|
||||
.inSeekStream = @ptrCast(*ElfSeekStream, &fileSeekStream.stream),
|
||||
.outStream = @ptrCast(*BinOutStream, &outFileOutStream.stream),
|
||||
.outSeekStream = @ptrCast(*BinSeekStream, &outFileSeekStream.stream),
|
||||
};
|
||||
|
||||
var binaryElfOutput = BinaryElfOutput.init(arena_allocator);
|
||||
defer binaryElfOutput.deinit();
|
||||
|
||||
try binaryElfOutput.parseElf(elfFile);
|
||||
|
||||
for (binaryElfOutput.sections.toSlice()) |section| {
|
||||
try writeBinaryElfSection(allocator, writeContext, section);
|
||||
for (binary_elf_output.sections.toSlice()) |section| {
|
||||
try writeBinaryElfSection(elf_file, out_file, section);
|
||||
}
|
||||
}
|
||||
|
||||
@ -250,6 +214,6 @@ pub const InstallRawStep = struct {
|
||||
const full_dest_path = builder.getInstallPath(self.dest_dir, self.dest_filename);
|
||||
|
||||
fs.cwd().makePath(builder.getInstallPath(self.dest_dir, "")) catch unreachable;
|
||||
try emit_raw(builder.allocator, full_src_path, full_dest_path);
|
||||
try emitRaw(builder.allocator, full_src_path, full_dest_path);
|
||||
}
|
||||
};
|
||||
|
292
lib/std/elf.zig
292
lib/std/elf.zig
@ -330,9 +330,7 @@ pub const ET = extern enum(u16) {
|
||||
pub const HIPROC = 0xffff;
|
||||
};
|
||||
|
||||
pub const SectionHeader = Elf64_Shdr;
|
||||
pub const ProgramHeader = Elf64_Phdr;
|
||||
|
||||
/// All integers are native endian.
|
||||
const Header = struct {
|
||||
endian: builtin.Endian,
|
||||
is_64: bool,
|
||||
@ -346,9 +344,9 @@ const Header = struct {
|
||||
shstrndx: u16,
|
||||
};
|
||||
|
||||
pub fn readHeader(in_stream: var) !Header {
|
||||
pub fn readHeader(file: File) !Header {
|
||||
var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;
|
||||
try in_stream.readAll(&hdr_buf);
|
||||
try in_stream.preadAll(&hdr_buf, 0);
|
||||
const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf);
|
||||
const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf);
|
||||
if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
|
||||
@ -381,216 +379,86 @@ pub fn readHeader(in_stream: var) !Header {
|
||||
});
|
||||
}
|
||||
|
||||
pub const Elf = struct {
|
||||
seekable_stream: *io.SeekableStream(anyerror, anyerror),
|
||||
in_stream: *io.InStream(anyerror),
|
||||
is_64: bool,
|
||||
endian: builtin.Endian,
|
||||
file_type: ET,
|
||||
arch: EM,
|
||||
entry_addr: u64,
|
||||
program_header_offset: u64,
|
||||
section_header_offset: u64,
|
||||
string_section_index: usize,
|
||||
string_section: *SectionHeader,
|
||||
section_headers: []SectionHeader,
|
||||
program_headers: []ProgramHeader,
|
||||
/// All integers are native endian.
|
||||
pub const AllHeaders = struct {
|
||||
header: Header,
|
||||
section_headers: []Elf64_Shdr,
|
||||
program_headers: []Elf64_Phdr,
|
||||
allocator: *mem.Allocator,
|
||||
|
||||
pub fn openStream(
|
||||
allocator: *mem.Allocator,
|
||||
seekable_stream: *io.SeekableStream(anyerror, anyerror),
|
||||
in: *io.InStream(anyerror),
|
||||
) !Elf {
|
||||
var elf: Elf = undefined;
|
||||
elf.allocator = allocator;
|
||||
elf.seekable_stream = seekable_stream;
|
||||
elf.in_stream = in;
|
||||
|
||||
var magic: [4]u8 = undefined;
|
||||
try in.readNoEof(magic[0..]);
|
||||
if (!mem.eql(u8, &magic, "\x7fELF")) return error.InvalidFormat;
|
||||
|
||||
elf.is_64 = switch (try in.readByte()) {
|
||||
1 => false,
|
||||
2 => true,
|
||||
else => return error.InvalidFormat,
|
||||
};
|
||||
|
||||
elf.endian = switch (try in.readByte()) {
|
||||
1 => .Little,
|
||||
2 => .Big,
|
||||
else => return error.InvalidFormat,
|
||||
};
|
||||
|
||||
const version_byte = try in.readByte();
|
||||
if (version_byte != 1) return error.InvalidFormat;
|
||||
|
||||
// skip over padding
|
||||
try seekable_stream.seekBy(9);
|
||||
|
||||
elf.file_type = try in.readEnum(ET, elf.endian);
|
||||
elf.arch = try in.readEnum(EM, elf.endian);
|
||||
|
||||
const elf_version = try in.readInt(u32, elf.endian);
|
||||
if (elf_version != 1) return error.InvalidFormat;
|
||||
|
||||
if (elf.is_64) {
|
||||
elf.entry_addr = try in.readInt(u64, elf.endian);
|
||||
elf.program_header_offset = try in.readInt(u64, elf.endian);
|
||||
elf.section_header_offset = try in.readInt(u64, elf.endian);
|
||||
} else {
|
||||
elf.entry_addr = @as(u64, try in.readInt(u32, elf.endian));
|
||||
elf.program_header_offset = @as(u64, try in.readInt(u32, elf.endian));
|
||||
elf.section_header_offset = @as(u64, try in.readInt(u32, elf.endian));
|
||||
}
|
||||
|
||||
// skip over flags
|
||||
try seekable_stream.seekBy(4);
|
||||
|
||||
const header_size = try in.readInt(u16, elf.endian);
|
||||
if ((elf.is_64 and header_size != @sizeOf(Elf64_Ehdr)) or (!elf.is_64 and header_size != @sizeOf(Elf32_Ehdr))) {
|
||||
return error.InvalidFormat;
|
||||
}
|
||||
|
||||
const ph_entry_size = try in.readInt(u16, elf.endian);
|
||||
const ph_entry_count = try in.readInt(u16, elf.endian);
|
||||
|
||||
if ((elf.is_64 and ph_entry_size != @sizeOf(Elf64_Phdr)) or (!elf.is_64 and ph_entry_size != @sizeOf(Elf32_Phdr))) {
|
||||
return error.InvalidFormat;
|
||||
}
|
||||
|
||||
const sh_entry_size = try in.readInt(u16, elf.endian);
|
||||
const sh_entry_count = try in.readInt(u16, elf.endian);
|
||||
|
||||
if ((elf.is_64 and sh_entry_size != @sizeOf(Elf64_Shdr)) or (!elf.is_64 and sh_entry_size != @sizeOf(Elf32_Shdr))) {
|
||||
return error.InvalidFormat;
|
||||
}
|
||||
|
||||
elf.string_section_index = @as(usize, try in.readInt(u16, elf.endian));
|
||||
|
||||
if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat;
|
||||
|
||||
const sh_byte_count = @as(u64, sh_entry_size) * @as(u64, sh_entry_count);
|
||||
const end_sh = try math.add(u64, elf.section_header_offset, sh_byte_count);
|
||||
const ph_byte_count = @as(u64, ph_entry_size) * @as(u64, ph_entry_count);
|
||||
const end_ph = try math.add(u64, elf.program_header_offset, ph_byte_count);
|
||||
|
||||
const stream_end = try seekable_stream.getEndPos();
|
||||
if (stream_end < end_sh or stream_end < end_ph) {
|
||||
return error.InvalidFormat;
|
||||
}
|
||||
|
||||
try seekable_stream.seekTo(elf.program_header_offset);
|
||||
|
||||
elf.program_headers = try elf.allocator.alloc(ProgramHeader, ph_entry_count);
|
||||
errdefer elf.allocator.free(elf.program_headers);
|
||||
|
||||
if (elf.is_64) {
|
||||
for (elf.program_headers) |*elf_program| {
|
||||
elf_program.p_type = try in.readInt(Elf64_Word, elf.endian);
|
||||
elf_program.p_flags = try in.readInt(Elf64_Word, elf.endian);
|
||||
elf_program.p_offset = try in.readInt(Elf64_Off, elf.endian);
|
||||
elf_program.p_vaddr = try in.readInt(Elf64_Addr, elf.endian);
|
||||
elf_program.p_paddr = try in.readInt(Elf64_Addr, elf.endian);
|
||||
elf_program.p_filesz = try in.readInt(Elf64_Xword, elf.endian);
|
||||
elf_program.p_memsz = try in.readInt(Elf64_Xword, elf.endian);
|
||||
elf_program.p_align = try in.readInt(Elf64_Xword, elf.endian);
|
||||
}
|
||||
} else {
|
||||
for (elf.program_headers) |*elf_program| {
|
||||
elf_program.p_type = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian));
|
||||
elf_program.p_offset = @as(Elf64_Off, try in.readInt(Elf32_Off, elf.endian));
|
||||
elf_program.p_vaddr = @as(Elf64_Addr, try in.readInt(Elf32_Addr, elf.endian));
|
||||
elf_program.p_paddr = @as(Elf64_Addr, try in.readInt(Elf32_Addr, elf.endian));
|
||||
elf_program.p_filesz = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian));
|
||||
elf_program.p_memsz = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian));
|
||||
elf_program.p_flags = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian));
|
||||
elf_program.p_align = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian));
|
||||
}
|
||||
}
|
||||
|
||||
try seekable_stream.seekTo(elf.section_header_offset);
|
||||
|
||||
elf.section_headers = try elf.allocator.alloc(SectionHeader, sh_entry_count);
|
||||
errdefer elf.allocator.free(elf.section_headers);
|
||||
|
||||
if (elf.is_64) {
|
||||
for (elf.section_headers) |*elf_section| {
|
||||
elf_section.sh_name = try in.readInt(u32, elf.endian);
|
||||
elf_section.sh_type = try in.readInt(u32, elf.endian);
|
||||
elf_section.sh_flags = try in.readInt(u64, elf.endian);
|
||||
elf_section.sh_addr = try in.readInt(u64, elf.endian);
|
||||
elf_section.sh_offset = try in.readInt(u64, elf.endian);
|
||||
elf_section.sh_size = try in.readInt(u64, elf.endian);
|
||||
elf_section.sh_link = try in.readInt(u32, elf.endian);
|
||||
elf_section.sh_info = try in.readInt(u32, elf.endian);
|
||||
elf_section.sh_addralign = try in.readInt(u64, elf.endian);
|
||||
elf_section.sh_entsize = try in.readInt(u64, elf.endian);
|
||||
}
|
||||
} else {
|
||||
for (elf.section_headers) |*elf_section| {
|
||||
// TODO (multiple occurrences) allow implicit cast from %u32 -> %u64 ?
|
||||
elf_section.sh_name = try in.readInt(u32, elf.endian);
|
||||
elf_section.sh_type = try in.readInt(u32, elf.endian);
|
||||
elf_section.sh_flags = @as(u64, try in.readInt(u32, elf.endian));
|
||||
elf_section.sh_addr = @as(u64, try in.readInt(u32, elf.endian));
|
||||
elf_section.sh_offset = @as(u64, try in.readInt(u32, elf.endian));
|
||||
elf_section.sh_size = @as(u64, try in.readInt(u32, elf.endian));
|
||||
elf_section.sh_link = try in.readInt(u32, elf.endian);
|
||||
elf_section.sh_info = try in.readInt(u32, elf.endian);
|
||||
elf_section.sh_addralign = @as(u64, try in.readInt(u32, elf.endian));
|
||||
elf_section.sh_entsize = @as(u64, try in.readInt(u32, elf.endian));
|
||||
}
|
||||
}
|
||||
|
||||
for (elf.section_headers) |*elf_section| {
|
||||
if (elf_section.sh_type != SHT_NOBITS) {
|
||||
const file_end_offset = try math.add(u64, elf_section.sh_offset, elf_section.sh_size);
|
||||
if (stream_end < file_end_offset) return error.InvalidFormat;
|
||||
}
|
||||
}
|
||||
|
||||
elf.string_section = &elf.section_headers[elf.string_section_index];
|
||||
if (elf.string_section.sh_type != SHT_STRTAB) {
|
||||
// not a string table
|
||||
return error.InvalidFormat;
|
||||
}
|
||||
|
||||
return elf;
|
||||
}
|
||||
|
||||
pub fn close(elf: *Elf) void {
|
||||
elf.allocator.free(elf.section_headers);
|
||||
elf.allocator.free(elf.program_headers);
|
||||
}
|
||||
|
||||
pub fn findSection(elf: *Elf, name: []const u8) !?*SectionHeader {
|
||||
section_loop: for (elf.section_headers) |*elf_section| {
|
||||
if (elf_section.sh_type == SHT_NULL) continue;
|
||||
|
||||
const name_offset = elf.string_section.sh_offset + elf_section.sh_name;
|
||||
try elf.seekable_stream.seekTo(name_offset);
|
||||
|
||||
for (name) |expected_c| {
|
||||
const target_c = try elf.in_stream.readByte();
|
||||
if (target_c == 0 or expected_c != target_c) continue :section_loop;
|
||||
}
|
||||
|
||||
{
|
||||
const null_byte = try elf.in_stream.readByte();
|
||||
if (null_byte == 0) return elf_section;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn seekToSection(elf: *Elf, elf_section: *SectionHeader) !void {
|
||||
try elf.seekable_stream.seekTo(elf_section.sh_offset);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn readAllHeaders(allocator: *mem.Allocator, file: File) !AllHeaders {
|
||||
var hdrs: AllHeaders = .{
|
||||
.allocator = allocator,
|
||||
.header = try readHeader(file),
|
||||
.section_headers = undefined,
|
||||
.program_headers = undefined,
|
||||
};
|
||||
const is_64 = hdrs.header.is_64;
|
||||
const need_bswap = hdrs.header.endian != std.builtin.endian;
|
||||
|
||||
hdrs.section_headers = try allocator.alloc(Elf64_Shdr, hdrs.header.shnum);
|
||||
errdefer hdrs.allocator.free(hdrs.section_headers);
|
||||
|
||||
hdrs.program_headers = try allocator.alloc(Elf64_Phdr, hdrs.header.phnum);
|
||||
errdefer hdrs.allocator.free(hdrs.program_headers);
|
||||
|
||||
// Treat section headers and program headers as byte buffers. For 32-bit ELF and
|
||||
// non-matching endian files, we post-process to correct integer endianness and offsets.
|
||||
|
||||
const shdr_buf = std.mem.sliceToBytes(hdrs.section_headers)[0 .. hdrs.header.shentsize * hdrs.header.shnum];
|
||||
const phdr_buf = std.mem.sliceToBytes(hdrs.section_headers)[0 .. hdrs.header.phentsize * hdrs.header.phnum];
|
||||
|
||||
try file.preadAll(phdr_buf, hdrs.header.phoff);
|
||||
try file.preadAll(shdr_buf, hdrs.header.shoff);
|
||||
|
||||
const shdrs32 = @ptrCast([*]Elf32_Shdr, @alignCast(@alignOf(Elf32_Shdr), shdr_buf.ptr))[0..hdrs.header.shnum];
|
||||
const phdrs32 = @ptrCast([*]Elf32_Phdr, @alignCast(@alignOf(Elf32_Phdr), phdr_buf.ptr))[0..hdrs.header.phnum];
|
||||
for (hdrs.section_headers) |*shdr, i| {
|
||||
shdr.* = .{
|
||||
.sh_name = int(is_64, need_bswap, shdrs32[i].sh_name, shdr.sh_name),
|
||||
.sh_type = int(is_64, need_bswap, shdrs32[i].sh_type, shdr.sh_type),
|
||||
.sh_flags = int(is_64, need_bswap, shdrs32[i].sh_flags, shdr.sh_flags),
|
||||
.sh_addr = int(is_64, need_bswap, shdrs32[i].sh_addr, shdr.sh_addr),
|
||||
.sh_offset = int(is_64, need_bswap, shdrs32[i].sh_offset, shdr.sh_offset),
|
||||
.sh_size = int(is_64, need_bswap, shdrs32[i].sh_size, shdr.sh_size),
|
||||
.sh_link = int(is_64, need_bswap, shdrs32[i].sh_link, shdr.sh_link),
|
||||
.sh_info = int(is_64, need_bswap, shdrs32[i].sh_info, shdr.sh_info),
|
||||
.sh_addralign = int(is_64, need_bswap, shdrs32[i].sh_addralign, shdr.sh_addralign),
|
||||
.sh_entsize = int(is_64, need_bswap, shdrs32[i].sh_entsize, shdr.sh_entsize),
|
||||
};
|
||||
}
|
||||
for (hdrs.program_headers) |*phdr, i| {
|
||||
phdr.* = .{
|
||||
.p_type = int(is_64, need_bswap, phdrs32[i].p_type, shdr.p_type),
|
||||
.p_offset = int(is_64, need_bswap, phdrs32[i].p_offset, shdr.p_offset),
|
||||
.p_vaddr = int(is_64, need_bswap, phdrs32[i].p_vaddr, shdr.p_vaddr),
|
||||
.p_paddr = int(is_64, need_bswap, phdrs32[i].p_paddr, shdr.p_paddr),
|
||||
.p_filesz = int(is_64, need_bswap, phdrs32[i].p_filesz, shdr.p_filesz),
|
||||
.p_memsz = int(is_64, need_bswap, phdrs32[i].p_memsz, shdr.p_memsz),
|
||||
.p_flags = int(is_64, need_bswap, phdrs32[i].p_flags, shdr.p_flags),
|
||||
.p_align = int(is_64, need_bswap, phdrs32[i].p_align, shdr.p_align),
|
||||
};
|
||||
}
|
||||
return hdrs;
|
||||
}
|
||||
|
||||
pub fn int(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_64) {
|
||||
if (is_64) {
|
||||
if (need_bswap) {
|
||||
return @byteSwap(@TypeOf(int_64), int_64);
|
||||
} else {
|
||||
return int_64;
|
||||
}
|
||||
} else {
|
||||
if (need_bswap) {
|
||||
return @byteSwap(@TypeOf(int_32), int_32);
|
||||
} else {
|
||||
return int_32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const EI_NIDENT = 16;
|
||||
|
||||
pub const EI_CLASS = 4;
|
||||
|
@ -570,7 +570,7 @@ pub const NativeTargetInfo = struct {
|
||||
cross_target: CrossTarget,
|
||||
) AbiAndDynamicLinkerFromFileError!NativeTargetInfo {
|
||||
var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined;
|
||||
_ = try preadFull(file, &hdr_buf, 0, hdr_buf.len);
|
||||
_ = try preadMin(file, &hdr_buf, 0, hdr_buf.len);
|
||||
const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf);
|
||||
const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf);
|
||||
if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
|
||||
@ -587,6 +587,7 @@ pub const NativeTargetInfo = struct {
|
||||
elf.ELFCLASS64 => true,
|
||||
else => return error.InvalidElfClass,
|
||||
};
|
||||
const elfInt = elf.int;
|
||||
var phoff = elfInt(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff);
|
||||
const phentsize = elfInt(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize);
|
||||
const phnum = elfInt(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum);
|
||||
@ -610,7 +611,7 @@ pub const NativeTargetInfo = struct {
|
||||
// Reserve some bytes so that we can deref the 64-bit struct fields
|
||||
// even when the ELF file is 32-bits.
|
||||
const ph_reserve: usize = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr);
|
||||
const ph_read_byte_len = try preadFull(file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize);
|
||||
const ph_read_byte_len = try preadMin(file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize);
|
||||
var ph_buf_i: usize = 0;
|
||||
while (ph_buf_i < ph_read_byte_len and ph_i < phnum) : ({
|
||||
ph_i += 1;
|
||||
@ -625,7 +626,7 @@ pub const NativeTargetInfo = struct {
|
||||
const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
|
||||
const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
|
||||
if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong;
|
||||
_ = try preadFull(file, result.dynamic_linker.buffer[0..p_filesz], p_offset, p_filesz);
|
||||
_ = try preadMin(file, result.dynamic_linker.buffer[0..p_filesz], p_offset, p_filesz);
|
||||
// PT_INTERP includes a null byte in p_filesz.
|
||||
const len = p_filesz - 1;
|
||||
// dynamic_linker.max_byte is "max", not "len".
|
||||
@ -656,7 +657,7 @@ pub const NativeTargetInfo = struct {
|
||||
// Reserve some bytes so that we can deref the 64-bit struct fields
|
||||
// even when the ELF file is 32-bits.
|
||||
const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn);
|
||||
const dyn_read_byte_len = try preadFull(
|
||||
const dyn_read_byte_len = try preadMin(
|
||||
file,
|
||||
dyn_buf[0 .. dyn_buf.len - dyn_reserve],
|
||||
dyn_off,
|
||||
@ -701,14 +702,14 @@ pub const NativeTargetInfo = struct {
|
||||
var sh_buf: [16 * @sizeOf(elf.Elf64_Shdr)]u8 align(@alignOf(elf.Elf64_Shdr)) = undefined;
|
||||
if (sh_buf.len < shentsize) return error.InvalidElfFile;
|
||||
|
||||
_ = try preadFull(file, &sh_buf, str_section_off, shentsize);
|
||||
_ = try preadMin(file, &sh_buf, str_section_off, shentsize);
|
||||
const shstr32 = @ptrCast(*elf.Elf32_Shdr, @alignCast(@alignOf(elf.Elf32_Shdr), &sh_buf));
|
||||
const shstr64 = @ptrCast(*elf.Elf64_Shdr, @alignCast(@alignOf(elf.Elf64_Shdr), &sh_buf));
|
||||
const shstrtab_off = elfInt(is_64, need_bswap, shstr32.sh_offset, shstr64.sh_offset);
|
||||
const shstrtab_size = elfInt(is_64, need_bswap, shstr32.sh_size, shstr64.sh_size);
|
||||
var strtab_buf: [4096:0]u8 = undefined;
|
||||
const shstrtab_len = std.math.min(shstrtab_size, strtab_buf.len);
|
||||
const shstrtab_read_len = try preadFull(file, &strtab_buf, shstrtab_off, shstrtab_len);
|
||||
const shstrtab_read_len = try preadMin(file, &strtab_buf, shstrtab_off, shstrtab_len);
|
||||
const shstrtab = strtab_buf[0..shstrtab_read_len];
|
||||
|
||||
const shnum = elfInt(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum);
|
||||
@ -717,7 +718,7 @@ pub const NativeTargetInfo = struct {
|
||||
// Reserve some bytes so that we can deref the 64-bit struct fields
|
||||
// even when the ELF file is 32-bits.
|
||||
const sh_reserve: usize = @sizeOf(elf.Elf64_Shdr) - @sizeOf(elf.Elf32_Shdr);
|
||||
const sh_read_byte_len = try preadFull(
|
||||
const sh_read_byte_len = try preadMin(
|
||||
file,
|
||||
sh_buf[0 .. sh_buf.len - sh_reserve],
|
||||
shoff,
|
||||
@ -751,7 +752,7 @@ pub const NativeTargetInfo = struct {
|
||||
|
||||
if (dynstr) |ds| {
|
||||
const strtab_len = std.math.min(ds.size, strtab_buf.len);
|
||||
const strtab_read_len = try preadFull(file, &strtab_buf, ds.offset, shstrtab_len);
|
||||
const strtab_read_len = try preadMin(file, &strtab_buf, ds.offset, shstrtab_len);
|
||||
const strtab = strtab_buf[0..strtab_read_len];
|
||||
// TODO this pointer cast should not be necessary
|
||||
const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr));
|
||||
@ -813,7 +814,7 @@ pub const NativeTargetInfo = struct {
|
||||
return result;
|
||||
}
|
||||
|
||||
fn preadFull(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usize {
|
||||
fn preadMin(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usize {
|
||||
var i: u64 = 0;
|
||||
while (i < min_read_len) {
|
||||
const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) {
|
||||
@ -853,22 +854,6 @@ pub const NativeTargetInfo = struct {
|
||||
abi: Target.Abi,
|
||||
};
|
||||
|
||||
fn elfInt(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_64) {
|
||||
if (is_64) {
|
||||
if (need_bswap) {
|
||||
return @byteSwap(@TypeOf(int_64), int_64);
|
||||
} else {
|
||||
return int_64;
|
||||
}
|
||||
} else {
|
||||
if (need_bswap) {
|
||||
return @byteSwap(@TypeOf(int_32), int_32);
|
||||
} else {
|
||||
return int_32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn detectNativeCpuAndFeatures(cpu_arch: Target.Cpu.Arch, os: Target.Os, cross_target: CrossTarget) ?Target.Cpu {
|
||||
// Here we switch on a comptime value rather than `cpu_arch`. This is valid because `cpu_arch`,
|
||||
// although it is a runtime value, is guaranteed to be one of the architectures in the set
|
||||
|
Loading…
Reference in New Issue
Block a user