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