| ... | ... | @@ -505,6 +505,7 @@ pub const AbiAndDynamicLinkerFromFileError = error{ |
| 505 | 505 | UnexpectedEndOfFile, |
| 506 | 506 | NameTooLong, |
| 507 | 507 | ProcessNotFound, |
| 508 | StaticElfFile, |
| 508 | 509 | }; |
| 509 | 510 | |
| 510 | 511 | pub fn abiAndDynamicLinkerFromFile( |
| ... | ... | @@ -550,6 +551,8 @@ pub fn abiAndDynamicLinkerFromFile( |
| 550 | 551 | if (phentsize > @sizeOf(elf.Elf64_Phdr)) return error.InvalidElfFile; |
| 551 | 552 | |
| 552 | 553 | var ph_i: u16 = 0; |
| 554 | var got_dyn_section: bool = false; |
| 555 | |
| 553 | 556 | while (ph_i < phnum) { |
| 554 | 557 | // Reserve some bytes so that we can deref the 64-bit struct fields |
| 555 | 558 | // even when the ELF file is 32-bits. |
| ... | ... | @@ -565,61 +568,69 @@ pub fn abiAndDynamicLinkerFromFile( |
| 565 | 568 | const ph64: *elf.Elf64_Phdr = @ptrCast(@alignCast(&ph_buf[ph_buf_i])); |
| 566 | 569 | const p_type = elfInt(is_64, need_bswap, ph32.p_type, ph64.p_type); |
| 567 | 570 | switch (p_type) { |
| 568 | | elf.PT_INTERP => if (look_for_ld) { |
| 569 | | const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); |
| 570 | | const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); |
| 571 | | if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong; |
| 572 | | const filesz: usize = @intCast(p_filesz); |
| 573 | | _ = try preadAtLeast(file, result.dynamic_linker.buffer[0..filesz], p_offset, filesz); |
| 574 | | // PT_INTERP includes a null byte in filesz. |
| 575 | | const len = filesz - 1; |
| 576 | | // dynamic_linker.max_byte is "max", not "len". |
| 577 | | // We know it will fit in u8 because we check against dynamic_linker.buffer.len above. |
| 578 | | result.dynamic_linker.len = @intCast(len); |
| 579 | | |
| 580 | | // Use it to determine ABI. |
| 581 | | const full_ld_path = result.dynamic_linker.buffer[0..len]; |
| 582 | | for (ld_info_list) |ld_info| { |
| 583 | | const standard_ld_basename = fs.path.basename(ld_info.ld.get().?); |
| 584 | | if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) { |
| 585 | | result.abi = ld_info.abi; |
| 586 | | break; |
| 571 | elf.PT_INTERP => { |
| 572 | got_dyn_section = true; |
| 573 | |
| 574 | if (look_for_ld) { |
| 575 | const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); |
| 576 | const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); |
| 577 | if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong; |
| 578 | const filesz: usize = @intCast(p_filesz); |
| 579 | _ = try preadAtLeast(file, result.dynamic_linker.buffer[0..filesz], p_offset, filesz); |
| 580 | // PT_INTERP includes a null byte in filesz. |
| 581 | const len = filesz - 1; |
| 582 | // dynamic_linker.max_byte is "max", not "len". |
| 583 | // We know it will fit in u8 because we check against dynamic_linker.buffer.len above. |
| 584 | result.dynamic_linker.len = @intCast(len); |
| 585 | |
| 586 | // Use it to determine ABI. |
| 587 | const full_ld_path = result.dynamic_linker.buffer[0..len]; |
| 588 | for (ld_info_list) |ld_info| { |
| 589 | const standard_ld_basename = fs.path.basename(ld_info.ld.get().?); |
| 590 | if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) { |
| 591 | result.abi = ld_info.abi; |
| 592 | break; |
| 593 | } |
| 587 | 594 | } |
| 588 | 595 | } |
| 589 | 596 | }, |
| 590 | 597 | // We only need this for detecting glibc version. |
| 591 | | elf.PT_DYNAMIC => if (builtin.target.os.tag == .linux and result.isGnuLibC() and |
| 592 | | query.glibc_version == null) |
| 593 | | { |
| 594 | | var dyn_off = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); |
| 595 | | const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); |
| 596 | | const dyn_size: usize = if (is_64) @sizeOf(elf.Elf64_Dyn) else @sizeOf(elf.Elf32_Dyn); |
| 597 | | const dyn_num = p_filesz / dyn_size; |
| 598 | | var dyn_buf: [16 * @sizeOf(elf.Elf64_Dyn)]u8 align(@alignOf(elf.Elf64_Dyn)) = undefined; |
| 599 | | var dyn_i: usize = 0; |
| 600 | | dyn: while (dyn_i < dyn_num) { |
| 601 | | // Reserve some bytes so that we can deref the 64-bit struct fields |
| 602 | | // even when the ELF file is 32-bits. |
| 603 | | const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn); |
| 604 | | const dyn_read_byte_len = try preadAtLeast( |
| 605 | | file, |
| 606 | | dyn_buf[0 .. dyn_buf.len - dyn_reserve], |
| 607 | | dyn_off, |
| 608 | | dyn_size, |
| 609 | | ); |
| 610 | | var dyn_buf_i: usize = 0; |
| 611 | | while (dyn_buf_i < dyn_read_byte_len and dyn_i < dyn_num) : ({ |
| 612 | | dyn_i += 1; |
| 613 | | dyn_off += dyn_size; |
| 614 | | dyn_buf_i += dyn_size; |
| 615 | | }) { |
| 616 | | const dyn32: *elf.Elf32_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i])); |
| 617 | | const dyn64: *elf.Elf64_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i])); |
| 618 | | const tag = elfInt(is_64, need_bswap, dyn32.d_tag, dyn64.d_tag); |
| 619 | | const val = elfInt(is_64, need_bswap, dyn32.d_val, dyn64.d_val); |
| 620 | | if (tag == elf.DT_RUNPATH) { |
| 621 | | rpath_offset = val; |
| 622 | | break :dyn; |
| 598 | elf.PT_DYNAMIC => { |
| 599 | got_dyn_section = true; |
| 600 | |
| 601 | if (builtin.target.os.tag == .linux and result.isGnuLibC() and |
| 602 | query.glibc_version == null) |
| 603 | { |
| 604 | var dyn_off = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); |
| 605 | const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); |
| 606 | const dyn_size: usize = if (is_64) @sizeOf(elf.Elf64_Dyn) else @sizeOf(elf.Elf32_Dyn); |
| 607 | const dyn_num = p_filesz / dyn_size; |
| 608 | var dyn_buf: [16 * @sizeOf(elf.Elf64_Dyn)]u8 align(@alignOf(elf.Elf64_Dyn)) = undefined; |
| 609 | var dyn_i: usize = 0; |
| 610 | dyn: while (dyn_i < dyn_num) { |
| 611 | // Reserve some bytes so that we can deref the 64-bit struct fields |
| 612 | // even when the ELF file is 32-bits. |
| 613 | const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn); |
| 614 | const dyn_read_byte_len = try preadAtLeast( |
| 615 | file, |
| 616 | dyn_buf[0 .. dyn_buf.len - dyn_reserve], |
| 617 | dyn_off, |
| 618 | dyn_size, |
| 619 | ); |
| 620 | var dyn_buf_i: usize = 0; |
| 621 | while (dyn_buf_i < dyn_read_byte_len and dyn_i < dyn_num) : ({ |
| 622 | dyn_i += 1; |
| 623 | dyn_off += dyn_size; |
| 624 | dyn_buf_i += dyn_size; |
| 625 | }) { |
| 626 | const dyn32: *elf.Elf32_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i])); |
| 627 | const dyn64: *elf.Elf64_Dyn = @ptrCast(@alignCast(&dyn_buf[dyn_buf_i])); |
| 628 | const tag = elfInt(is_64, need_bswap, dyn32.d_tag, dyn64.d_tag); |
| 629 | const val = elfInt(is_64, need_bswap, dyn32.d_val, dyn64.d_val); |
| 630 | if (tag == elf.DT_RUNPATH) { |
| 631 | rpath_offset = val; |
| 632 | break :dyn; |
| 633 | } |
| 623 | 634 | } |
| 624 | 635 | } |
| 625 | 636 | } |
| ... | ... | @@ -629,6 +640,10 @@ pub fn abiAndDynamicLinkerFromFile( |
| 629 | 640 | } |
| 630 | 641 | } |
| 631 | 642 | |
| 643 | if (!got_dyn_section) { |
| 644 | return error.StaticElfFile; |
| 645 | } |
| 646 | |
| 632 | 647 | if (builtin.target.os.tag == .linux and result.isGnuLibC() and |
| 633 | 648 | query.glibc_version == null) |
| 634 | 649 | { |
| ... | ... | @@ -1208,6 +1223,7 @@ fn detectAbiAndDynamicLinker( |
| 1208 | 1223 | error.Unexpected, |
| 1209 | 1224 | error.UnexpectedEndOfFile, |
| 1210 | 1225 | error.NameTooLong, |
| 1226 | error.StaticElfFile, |
| 1211 | 1227 | // Finally, we fall back on the standard path. |
| 1212 | 1228 | => |e| { |
| 1213 | 1229 | std.log.warn("Encountered error: {s}, falling back to default ABI and dynamic linker.", .{@errorName(e)}); |