| ... | @@ -234,7 +234,14 @@ pub fn calcEhFrameSize(elf_file: *Elf) !usize { | ... | @@ -234,7 +234,14 @@ pub fn calcEhFrameSize(elf_file: *Elf) !usize { |
| 234 | return offset; | 234 | return offset; |
| 235 | } | 235 | } |
| 236 | | 236 | |
| | 237 | fn haveEhFrameHdrSearchTable(elf_file: *Elf) bool { |
| | 238 | // Seach table generation is not implemented for the ZigObject. Also, it would be wasteful to |
| | 239 | // re-do this work on every single incremental update. |
| | 240 | return elf_file.zigObjectPtr() == null; |
| | 241 | } |
| | 242 | |
| 237 | pub fn calcEhFrameHdrSize(elf_file: *Elf) usize { | 243 | pub fn calcEhFrameHdrSize(elf_file: *Elf) usize { |
| | 244 | if (!haveEhFrameHdrSearchTable(elf_file)) return 8; |
| 238 | var count: usize = 0; | 245 | var count: usize = 0; |
| 239 | for (elf_file.objects.items) |index| { | 246 | for (elf_file.objects.items) |index| { |
| 240 | for (elf_file.file(index).?.object.fdes.items) |fde| { | 247 | for (elf_file.file(index).?.object.fdes.items) |fde| { |
| ... | @@ -242,7 +249,7 @@ pub fn calcEhFrameHdrSize(elf_file: *Elf) usize { | ... | @@ -242,7 +249,7 @@ pub fn calcEhFrameHdrSize(elf_file: *Elf) usize { |
| 242 | count += 1; | 249 | count += 1; |
| 243 | } | 250 | } |
| 244 | } | 251 | } |
| 245 | return eh_frame_hdr_header_size + count * 8; | 252 | return 12 + count * 8; |
| 246 | } | 253 | } |
| 247 | | 254 | |
| 248 | pub fn calcEhFrameRelocs(elf_file: *Elf) usize { | 255 | pub fn calcEhFrameRelocs(elf_file: *Elf) usize { |
| ... | @@ -455,15 +462,23 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, relocs: *std.array_list.Managed(elf.El | ... | @@ -455,15 +462,23 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, relocs: *std.array_list.Managed(elf.El |
| 455 | } | 462 | } |
| 456 | | 463 | |
| 457 | pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void { | 464 | pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void { |
| | 465 | const endian = elf_file.getTarget().cpu.arch.endian(); |
| | 466 | const have_table = haveEhFrameHdrSearchTable(elf_file); |
| | 467 | |
| 458 | try writer.writeByte(1); // version | 468 | try writer.writeByte(1); // version |
| 459 | try writer.writeByte(@bitCast(@as(DW_EH_PE, .{ .type = .sdata4, .rel = .pcrel }))); // eh_frame_ptr_enc | 469 | try writer.writeByte(@bitCast(@as(DW_EH_PE, .{ .type = .sdata4, .rel = .pcrel }))); // eh_frame_ptr_enc |
| 460 | // Building the lookup table would be expensive work on every `flush` -- omit it. | 470 | if (have_table) { |
| 461 | try writer.writeByte(@bitCast(DW_EH_PE.omit)); // fde_count_enc | 471 | try writer.writeByte(@bitCast(@as(DW_EH_PE, .{ .type = .udata4, .rel = .abs }))); // fde_count_enc |
| 462 | try writer.writeByte(@bitCast(DW_EH_PE.omit)); // table_enc | 472 | try writer.writeByte(@bitCast(@as(DW_EH_PE, .{ .type = .sdata4, .rel = .datarel }))); // table_enc |
| | 473 | } else { |
| | 474 | try writer.writeByte(@bitCast(DW_EH_PE.omit)); // fde_count_enc |
| | 475 | try writer.writeByte(@bitCast(DW_EH_PE.omit)); // table_enc |
| | 476 | } |
| 463 | | 477 | |
| 464 | const shdrs = elf_file.sections.items(.shdr); | 478 | const shdrs = elf_file.sections.items(.shdr); |
| 465 | const eh_frame_shdr = shdrs[elf_file.section_indexes.eh_frame.?]; | 479 | const eh_frame_shdr = shdrs[elf_file.section_indexes.eh_frame.?]; |
| 466 | const eh_frame_hdr_shdr = shdrs[elf_file.section_indexes.eh_frame_hdr.?]; | 480 | const eh_frame_hdr_shdr = shdrs[elf_file.section_indexes.eh_frame_hdr.?]; |
| | 481 | // eh_frame_ptr |
| 467 | try writer.writeInt( | 482 | try writer.writeInt( |
| 468 | u32, | 483 | u32, |
| 469 | @as(u32, @bitCast(@as( | 484 | @as(u32, @bitCast(@as( |
| ... | @@ -472,9 +487,51 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void { | ... | @@ -472,9 +487,51 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void { |
| 472 | ))), | 487 | ))), |
| 473 | .little, | 488 | .little, |
| 474 | ); | 489 | ); |
| 475 | } | | |
| 476 | | 490 | |
| 477 | const eh_frame_hdr_header_size: usize = 12; | 491 | if (!have_table) return; |
| | 492 | |
| | 493 | const gpa = elf_file.base.comp.gpa; |
| | 494 | |
| | 495 | // This must be an `extern struct` because we will write the bytes directly to the file. |
| | 496 | const Entry = extern struct { |
| | 497 | first_pc_rel: i32, |
| | 498 | fde_addr_rel: i32, |
| | 499 | fn lessThan(_: void, lhs: @This(), rhs: @This()) bool { |
| | 500 | return lhs.first_pc_rel < rhs.first_pc_rel; |
| | 501 | } |
| | 502 | }; |
| | 503 | // The number of entries was already computed by `calcEhFrameHdrSize`. |
| | 504 | const num_fdes: u32 = @intCast(@divExact(eh_frame_hdr_shdr.sh_size - 12, 8)); |
| | 505 | try writer.writeInt(u32, num_fdes, endian); |
| | 506 | |
| | 507 | var entries: std.ArrayList(Entry) = try .initCapacity(gpa, num_fdes); |
| | 508 | defer entries.deinit(gpa); |
| | 509 | for (elf_file.objects.items) |file_index| { |
| | 510 | const object = elf_file.file(file_index).?.object; |
| | 511 | for (object.fdes.items) |fde| { |
| | 512 | if (!fde.alive) continue; |
| | 513 | const relocs = fde.relocs(object); |
| | 514 | // Should `relocs.len == 0` be an error? Things are completely broken anyhow in that case... |
| | 515 | const rel = relocs[0]; |
| | 516 | const ref = object.resolveSymbol(rel.r_sym(), elf_file); |
| | 517 | const sym = elf_file.symbol(ref).?; |
| | 518 | const fde_addr_abs: i64 = @intCast(fde.address(elf_file)); |
| | 519 | const fde_addr_rel: i64 = fde_addr_abs - @as(i64, @intCast(eh_frame_hdr_shdr.sh_addr)); |
| | 520 | const first_pc_abs: i64 = @as(i64, @intCast(sym.address(.{}, elf_file))) + rel.r_addend; |
| | 521 | const first_pc_rel: i64 = first_pc_abs - @as(i64, @intCast(eh_frame_hdr_shdr.sh_addr)); |
| | 522 | entries.appendAssumeCapacity(.{ |
| | 523 | .first_pc_rel = @truncate(first_pc_rel), |
| | 524 | .fde_addr_rel = @truncate(fde_addr_rel), |
| | 525 | }); |
| | 526 | } |
| | 527 | } |
| | 528 | assert(entries.items.len == num_fdes); |
| | 529 | std.mem.sort(Entry, entries.items, {}, Entry.lessThan); |
| | 530 | if (endian != builtin.cpu.arch.endian()) { |
| | 531 | std.mem.byteSwapAllElements(Entry, entries.items); |
| | 532 | } |
| | 533 | try writer.writeAll(@ptrCast(entries.items)); |
| | 534 | } |
| 478 | | 535 | |
| 479 | const x86_64 = struct { | 536 | const x86_64 = struct { |
| 480 | fn resolveReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela, source: i64, target: i64, data: []u8) !void { | 537 | fn resolveReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela, source: i64, target: i64, data: []u8) !void { |
| ... | @@ -538,3 +595,5 @@ const DW_EH_PE = std.dwarf.EH.PE; | ... | @@ -538,3 +595,5 @@ const DW_EH_PE = std.dwarf.EH.PE; |
| 538 | const Elf = @import("../Elf.zig"); | 595 | const Elf = @import("../Elf.zig"); |
| 539 | const Object = @import("Object.zig"); | 596 | const Object = @import("Object.zig"); |
| 540 | const Symbol = @import("Symbol.zig"); | 597 | const Symbol = @import("Symbol.zig"); |
| | 598 | |
| | 599 | const builtin = @import("builtin"); |