| ... | ... | @@ -234,7 +234,14 @@ pub fn calcEhFrameSize(elf_file: *Elf) !usize { |
| 234 | 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 | 243 | pub fn calcEhFrameHdrSize(elf_file: *Elf) usize { |
| 244 | if (!haveEhFrameHdrSearchTable(elf_file)) return 8; |
| 238 | 245 | var count: usize = 0; |
| 239 | 246 | for (elf_file.objects.items) |index| { |
| 240 | 247 | for (elf_file.file(index).?.object.fdes.items) |fde| { |
| ... | ... | @@ -242,7 +249,7 @@ pub fn calcEhFrameHdrSize(elf_file: *Elf) usize { |
| 242 | 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 | 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 | 462 | } |
| 456 | 463 | |
| 457 | 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 | 468 | try writer.writeByte(1); // version |
| 459 | 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. |
| 461 | | try writer.writeByte(@bitCast(DW_EH_PE.omit)); // fde_count_enc |
| 462 | | try writer.writeByte(@bitCast(DW_EH_PE.omit)); // table_enc |
| 470 | if (have_table) { |
| 471 | try writer.writeByte(@bitCast(@as(DW_EH_PE, .{ .type = .udata4, .rel = .abs }))); // fde_count_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 | 478 | const shdrs = elf_file.sections.items(.shdr); |
| 465 | 479 | const eh_frame_shdr = shdrs[elf_file.section_indexes.eh_frame.?]; |
| 466 | 480 | const eh_frame_hdr_shdr = shdrs[elf_file.section_indexes.eh_frame_hdr.?]; |
| 481 | // eh_frame_ptr |
| 467 | 482 | try writer.writeInt( |
| 468 | 483 | u32, |
| 469 | 484 | @as(u32, @bitCast(@as( |
| ... | ... | @@ -472,9 +487,51 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void { |
| 472 | 487 | ))), |
| 473 | 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 | 536 | const x86_64 = struct { |
| 480 | 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 | 595 | const Elf = @import("../Elf.zig"); |
| 539 | 596 | const Object = @import("Object.zig"); |
| 540 | 597 | const Symbol = @import("Symbol.zig"); |
| 598 | |
| 599 | const builtin = @import("builtin"); |