objcopy: delete most of it

this code is not up to zig project standards

tracked by #24522

oh, and fix not adjusting buffer seek position in std.fs.File.Reader
This commit is contained in:
Andrew Kelley 2025-07-20 16:43:47 -07:00
parent f2a3ac7c05
commit f1576ef14c
5 changed files with 240 additions and 1142 deletions

File diff suppressed because it is too large Load Diff

View File

@ -482,6 +482,7 @@ pub const Header = struct {
is_64: bool, is_64: bool,
endian: std.builtin.Endian, endian: std.builtin.Endian,
os_abi: OSABI, os_abi: OSABI,
/// The meaning of this value depends on `os_abi`.
abi_version: u8, abi_version: u8,
type: ET, type: ET,
machine: EM, machine: EM,
@ -494,121 +495,92 @@ pub const Header = struct {
shnum: u16, shnum: u16,
shstrndx: u16, shstrndx: u16,
pub fn program_header_iterator(self: Header, parse_source: anytype) ProgramHeaderIterator(@TypeOf(parse_source)) { pub fn iterateProgramHeaders(h: Header, file_reader: *std.fs.File.Reader) ProgramHeaderIterator {
return ProgramHeaderIterator(@TypeOf(parse_source)){ return .{
.elf_header = self, .elf_header = h,
.parse_source = parse_source, .file_reader = file_reader,
}; };
} }
pub fn section_header_iterator(self: Header, parse_source: anytype) SectionHeaderIterator(@TypeOf(parse_source)) { pub fn iterateSectionHeaders(h: Header, file_reader: *std.fs.File.Reader) SectionHeaderIterator {
return SectionHeaderIterator(@TypeOf(parse_source)){ return .{
.elf_header = self, .elf_header = h,
.parse_source = parse_source, .file_reader = file_reader,
}; };
} }
pub fn read(parse_source: anytype) !Header { pub const ReadError = std.Io.Reader.Error || error{
var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined; InvalidElfMagic,
try parse_source.seekableStream().seekTo(0); InvalidElfVersion,
try parse_source.deprecatedReader().readNoEof(&hdr_buf); InvalidElfClass,
return Header.parse(&hdr_buf); InvalidElfEndian,
}
pub fn parse(hdr_buf: *align(@alignOf(Elf64_Ehdr)) const [@sizeOf(Elf64_Ehdr)]u8) !Header {
const hdr32 = @as(*const Elf32_Ehdr, @ptrCast(hdr_buf));
const hdr64 = @as(*const Elf64_Ehdr, @ptrCast(hdr_buf));
if (!mem.eql(u8, hdr32.e_ident[0..4], MAGIC)) return error.InvalidElfMagic;
if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion;
const is_64 = switch (hdr32.e_ident[EI_CLASS]) {
ELFCLASS32 => false,
ELFCLASS64 => true,
else => return error.InvalidElfClass,
}; };
const endian: std.builtin.Endian = switch (hdr32.e_ident[EI_DATA]) { pub fn read(r: *std.Io.Reader) ReadError!Header {
const buf = try r.peek(@sizeOf(Elf64_Ehdr));
if (!mem.eql(u8, buf[0..4], MAGIC)) return error.InvalidElfMagic;
if (buf[EI_VERSION] != 1) return error.InvalidElfVersion;
const endian: std.builtin.Endian = switch (buf[EI_DATA]) {
ELFDATA2LSB => .little, ELFDATA2LSB => .little,
ELFDATA2MSB => .big, ELFDATA2MSB => .big,
else => return error.InvalidElfEndian, else => return error.InvalidElfEndian,
}; };
const need_bswap = endian != native_endian;
return switch (buf[EI_CLASS]) {
ELFCLASS32 => .init(try r.takeStruct(Elf32_Ehdr, endian), endian),
ELFCLASS64 => .init(try r.takeStruct(Elf64_Ehdr, endian), endian),
else => return error.InvalidElfClass,
};
}
pub fn init(hdr: anytype, endian: std.builtin.Endian) Header {
// Converting integers to exhaustive enums using `@enumFromInt` could cause a panic. // Converting integers to exhaustive enums using `@enumFromInt` could cause a panic.
comptime assert(!@typeInfo(OSABI).@"enum".is_exhaustive); comptime assert(!@typeInfo(OSABI).@"enum".is_exhaustive);
const os_abi: OSABI = @enumFromInt(hdr32.e_ident[EI_OSABI]); return .{
.is_64 = switch (@TypeOf(hdr)) {
// The meaning of this value depends on `os_abi` so just make it available as `u8`. Elf32_Ehdr => false,
const abi_version = hdr32.e_ident[EI_ABIVERSION]; Elf64_Ehdr => true,
else => @compileError("bad type"),
const @"type" = if (need_bswap) blk: { },
comptime assert(!@typeInfo(ET).@"enum".is_exhaustive);
const value = @intFromEnum(hdr32.e_type);
break :blk @as(ET, @enumFromInt(@byteSwap(value)));
} else hdr32.e_type;
const machine = if (need_bswap) blk: {
comptime assert(!@typeInfo(EM).@"enum".is_exhaustive);
const value = @intFromEnum(hdr32.e_machine);
break :blk @as(EM, @enumFromInt(@byteSwap(value)));
} else hdr32.e_machine;
return @as(Header, .{
.is_64 = is_64,
.endian = endian, .endian = endian,
.os_abi = os_abi, .os_abi = @enumFromInt(hdr.e_ident[EI_OSABI]),
.abi_version = abi_version, .abi_version = hdr.e_ident[EI_ABIVERSION],
.type = @"type", .type = hdr.e_type,
.machine = machine, .machine = hdr.e_machine,
.entry = int(is_64, need_bswap, hdr32.e_entry, hdr64.e_entry), .entry = hdr.e_entry,
.phoff = int(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff), .phoff = hdr.e_phoff,
.shoff = int(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff), .shoff = hdr.e_shoff,
.phentsize = int(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize), .phentsize = hdr.e_phentsize,
.phnum = int(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum), .phnum = hdr.e_phnum,
.shentsize = int(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize), .shentsize = hdr.e_shentsize,
.shnum = int(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum), .shnum = hdr.e_shnum,
.shstrndx = int(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx), .shstrndx = hdr.e_shstrndx,
}); };
} }
}; };
pub fn ProgramHeaderIterator(comptime ParseSource: anytype) type { pub const ProgramHeaderIterator = struct {
return struct {
elf_header: Header, elf_header: Header,
parse_source: ParseSource, file_reader: *std.fs.File.Reader,
index: usize = 0, index: usize = 0,
pub fn next(self: *@This()) !?Elf64_Phdr { pub fn next(it: *ProgramHeaderIterator) !?Elf64_Phdr {
if (self.index >= self.elf_header.phnum) return null; if (it.index >= it.elf_header.phnum) return null;
defer self.index += 1; defer it.index += 1;
if (self.elf_header.is_64) { if (it.elf_header.is_64) {
var phdr: Elf64_Phdr = undefined; const offset = it.elf_header.phoff + @sizeOf(Elf64_Phdr) * it.index;
const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index; try it.file_reader.seekTo(offset);
try self.parse_source.seekableStream().seekTo(offset); const phdr = try it.file_reader.interface.takeStruct(Elf64_Phdr, it.elf_header.endian);
try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&phdr));
// ELF endianness matches native endianness.
if (self.elf_header.endian == native_endian) return phdr;
// Convert fields to native endianness.
mem.byteSwapAllFields(Elf64_Phdr, &phdr);
return phdr; return phdr;
} }
var phdr: Elf32_Phdr = undefined; const offset = it.elf_header.phoff + @sizeOf(Elf32_Phdr) * it.index;
const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index; try it.file_reader.seekTo(offset);
try self.parse_source.seekableStream().seekTo(offset); const phdr = try it.file_reader.interface.takeStruct(Elf32_Phdr, it.elf_header.endian);
try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&phdr)); return .{
// ELF endianness does NOT match native endianness.
if (self.elf_header.endian != native_endian) {
// Convert fields to native endianness.
mem.byteSwapAllFields(Elf32_Phdr, &phdr);
}
// Convert 32-bit header to 64-bit.
return Elf64_Phdr{
.p_type = phdr.p_type, .p_type = phdr.p_type,
.p_offset = phdr.p_offset, .p_offset = phdr.p_offset,
.p_vaddr = phdr.p_vaddr, .p_vaddr = phdr.p_vaddr,
@ -619,46 +591,26 @@ pub fn ProgramHeaderIterator(comptime ParseSource: anytype) type {
.p_align = phdr.p_align, .p_align = phdr.p_align,
}; };
} }
}; };
}
pub fn SectionHeaderIterator(comptime ParseSource: anytype) type { pub const SectionHeaderIterator = struct {
return struct {
elf_header: Header, elf_header: Header,
parse_source: ParseSource, file_reader: *std.fs.File.Reader,
index: usize = 0, index: usize = 0,
pub fn next(self: *@This()) !?Elf64_Shdr { pub fn next(it: *SectionHeaderIterator) !?Elf64_Shdr {
if (self.index >= self.elf_header.shnum) return null; if (it.index >= it.elf_header.shnum) return null;
defer self.index += 1; defer it.index += 1;
if (self.elf_header.is_64) { if (it.elf_header.is_64) {
var shdr: Elf64_Shdr = undefined; try it.file_reader.seekTo(it.elf_header.shoff + @sizeOf(Elf64_Shdr) * it.index);
const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index; const shdr = try it.file_reader.interface.takeStruct(Elf64_Shdr, it.elf_header.endian);
try self.parse_source.seekableStream().seekTo(offset);
try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&shdr));
// ELF endianness matches native endianness.
if (self.elf_header.endian == native_endian) return shdr;
// Convert fields to native endianness.
mem.byteSwapAllFields(Elf64_Shdr, &shdr);
return shdr; return shdr;
} }
var shdr: Elf32_Shdr = undefined; try it.file_reader.seekTo(it.elf_header.shoff + @sizeOf(Elf32_Shdr) * it.index);
const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index; const shdr = try it.file_reader.interface.takeStruct(Elf32_Shdr, it.elf_header.endian);
try self.parse_source.seekableStream().seekTo(offset); return .{
try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&shdr));
// ELF endianness does NOT match native endianness.
if (self.elf_header.endian != native_endian) {
// Convert fields to native endianness.
mem.byteSwapAllFields(Elf32_Shdr, &shdr);
}
// Convert 32-bit header to 64-bit.
return Elf64_Shdr{
.sh_name = shdr.sh_name, .sh_name = shdr.sh_name,
.sh_type = shdr.sh_type, .sh_type = shdr.sh_type,
.sh_flags = shdr.sh_flags, .sh_flags = shdr.sh_flags,
@ -671,28 +623,7 @@ pub fn SectionHeaderIterator(comptime ParseSource: anytype) type {
.sh_entsize = shdr.sh_entsize, .sh_entsize = shdr.sh_entsize,
}; };
} }
}; };
}
fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {
if (is_64) {
if (need_bswap) {
return @byteSwap(int_64);
} else {
return int_64;
}
} else {
return int32(need_bswap, int_32, @TypeOf(int_64));
}
}
fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {
if (need_bswap) {
return @byteSwap(int_32);
} else {
return int_32;
}
}
pub const ELFCLASSNONE = 0; pub const ELFCLASSNONE = 0;
pub const ELFCLASS32 = 1; pub const ELFCLASS32 = 1;

View File

@ -1228,14 +1228,12 @@ pub const Reader = struct {
pub fn seekBy(r: *Reader, offset: i64) Reader.SeekError!void { pub fn seekBy(r: *Reader, offset: i64) Reader.SeekError!void {
switch (r.mode) { switch (r.mode) {
.positional, .positional_reading => { .positional, .positional_reading => {
// TODO: make += operator allow any integer types setPosAdjustingBuffer(r, @intCast(@as(i64, @intCast(r.pos)) + offset));
r.pos = @intCast(@as(i64, @intCast(r.pos)) + offset);
}, },
.streaming, .streaming_reading => { .streaming, .streaming_reading => {
const seek_err = r.seek_err orelse e: { const seek_err = r.seek_err orelse e: {
if (posix.lseek_CUR(r.file.handle, offset)) |_| { if (posix.lseek_CUR(r.file.handle, offset)) |_| {
// TODO: make += operator allow any integer types setPosAdjustingBuffer(r, @intCast(@as(i64, @intCast(r.pos)) + offset));
r.pos = @intCast(@as(i64, @intCast(r.pos)) + offset);
return; return;
} else |err| { } else |err| {
r.seek_err = err; r.seek_err = err;
@ -1251,6 +1249,8 @@ pub const Reader = struct {
r.pos += n; r.pos += n;
remaining -= n; remaining -= n;
} }
r.interface.seek = 0;
r.interface.end = 0;
}, },
.failure => return r.seek_err.?, .failure => return r.seek_err.?,
} }
@ -1259,7 +1259,7 @@ pub const Reader = struct {
pub fn seekTo(r: *Reader, offset: u64) Reader.SeekError!void { pub fn seekTo(r: *Reader, offset: u64) Reader.SeekError!void {
switch (r.mode) { switch (r.mode) {
.positional, .positional_reading => { .positional, .positional_reading => {
r.pos = offset; setPosAdjustingBuffer(r, offset);
}, },
.streaming, .streaming_reading => { .streaming, .streaming_reading => {
if (offset >= r.pos) return Reader.seekBy(r, @intCast(offset - r.pos)); if (offset >= r.pos) return Reader.seekBy(r, @intCast(offset - r.pos));
@ -1268,12 +1268,22 @@ pub const Reader = struct {
r.seek_err = err; r.seek_err = err;
return err; return err;
}; };
r.pos = offset; setPosAdjustingBuffer(r, offset);
}, },
.failure => return r.seek_err.?, .failure => return r.seek_err.?,
} }
} }
fn setPosAdjustingBuffer(r: *Reader, offset: u64) void {
if (offset < r.pos or offset >= r.pos + r.interface.bufferedLen()) {
r.interface.seek = 0;
r.interface.end = 0;
} else {
r.interface.seek += @intCast(offset - r.pos);
}
r.pos = offset;
}
/// Number of slices to store on the stack, when trying to send as many byte /// Number of slices to store on the stack, when trying to send as many byte
/// vectors through the underlying read calls as possible. /// vectors through the underlying read calls as possible.
const max_buffers_len = 16; const max_buffers_len = 16;

View File

@ -65,69 +65,70 @@ pub fn build(b: *std.Build) void {
test_step.dependOn(&run_cmd.step); test_step.dependOn(&run_cmd.step);
} }
// Unwinding through a C shared library without a frame pointer (libc) // https://github.com/ziglang/zig/issues/24522
// //// Unwinding through a C shared library without a frame pointer (libc)
// getcontext version: libc ////
// //// getcontext version: libc
// Unwind info type: ////
// - ELF: DWARF .eh_frame + .debug_frame //// Unwind info type:
// - MachO: __unwind_info encodings: //// - ELF: DWARF .eh_frame + .debug_frame
// - x86_64: STACK_IMMD, STACK_IND //// - MachO: __unwind_info encodings:
// - aarch64: FRAMELESS, DWARF //// - x86_64: STACK_IMMD, STACK_IND
{ //// - aarch64: FRAMELESS, DWARF
const c_shared_lib = b.addLibrary(.{ //{
.linkage = .dynamic, // const c_shared_lib = b.addLibrary(.{
.name = "c_shared_lib", // .linkage = .dynamic,
.root_module = b.createModule(.{ // .name = "c_shared_lib",
.root_source_file = null, // .root_module = b.createModule(.{
.target = target, // .root_source_file = null,
.optimize = optimize, // .target = target,
.link_libc = true, // .optimize = optimize,
.strip = false, // .link_libc = true,
}), // .strip = false,
}); // }),
// });
if (target.result.os.tag == .windows) // if (target.result.os.tag == .windows)
c_shared_lib.root_module.addCMacro("LIB_API", "__declspec(dllexport)"); // c_shared_lib.root_module.addCMacro("LIB_API", "__declspec(dllexport)");
c_shared_lib.root_module.addCSourceFile(.{ // c_shared_lib.root_module.addCSourceFile(.{
.file = b.path("shared_lib.c"), // .file = b.path("shared_lib.c"),
.flags = &.{"-fomit-frame-pointer"}, // .flags = &.{"-fomit-frame-pointer"},
}); // });
const exe = b.addExecutable(.{ // const exe = b.addExecutable(.{
.name = "shared_lib_unwind", // .name = "shared_lib_unwind",
.root_module = b.createModule(.{ // .root_module = b.createModule(.{
.root_source_file = b.path("shared_lib_unwind.zig"), // .root_source_file = b.path("shared_lib_unwind.zig"),
.target = target, // .target = target,
.optimize = optimize, // .optimize = optimize,
.unwind_tables = if (target.result.os.tag.isDarwin()) .async else null, // .unwind_tables = if (target.result.os.tag.isDarwin()) .async else null,
.omit_frame_pointer = true, // .omit_frame_pointer = true,
}), // }),
// zig objcopy doesn't support incremental binaries // // zig objcopy doesn't support incremental binaries
.use_llvm = true, // .use_llvm = true,
}); // });
exe.linkLibrary(c_shared_lib); // exe.linkLibrary(c_shared_lib);
const run_cmd = b.addRunArtifact(exe); // const run_cmd = b.addRunArtifact(exe);
test_step.dependOn(&run_cmd.step); // test_step.dependOn(&run_cmd.step);
// Separate debug info ELF file // // Separate debug info ELF file
if (target.result.ofmt == .elf) { // if (target.result.ofmt == .elf) {
const filename = b.fmt("{s}_stripped", .{exe.out_filename}); // const filename = b.fmt("{s}_stripped", .{exe.out_filename});
const stripped_exe = b.addObjCopy(exe.getEmittedBin(), .{ // const stripped_exe = b.addObjCopy(exe.getEmittedBin(), .{
.basename = filename, // set the name for the debuglink // .basename = filename, // set the name for the debuglink
.compress_debug = true, // .compress_debug = true,
.strip = .debug, // .strip = .debug,
.extract_to_separate_file = true, // .extract_to_separate_file = true,
}); // });
const run_stripped = std.Build.Step.Run.create(b, b.fmt("run {s}", .{filename})); // const run_stripped = std.Build.Step.Run.create(b, b.fmt("run {s}", .{filename}));
run_stripped.addFileArg(stripped_exe.getOutput()); // run_stripped.addFileArg(stripped_exe.getOutput());
test_step.dependOn(&run_stripped.step); // test_step.dependOn(&run_stripped.step);
} // }
} //}
// Unwinding without libc/posix // Unwinding without libc/posix
// //

View File

@ -310,7 +310,8 @@ pub fn main() !void {
build_all_path, libc_so_path, @errorName(err), build_all_path, libc_so_path, @errorName(err),
}); });
}; };
const header = try elf.Header.parse(elf_bytes[0..@sizeOf(elf.Elf64_Ehdr)]); var stream: std.Io.Reader = .fixed(elf_bytes);
const header = try elf.Header.read(&stream);
const parse: Parse = .{ const parse: Parse = .{
.arena = arena, .arena = arena,