@@ -54,10 +54,35 @@ namespace detail {
5454
5555 Result<std::uintptr_t , internal_error> elf::get_module_image_base () {
5656 // get image base
57+ auto impl = [this ]<std::size_t Bits>() -> Result<std::uintptr_t , internal_error> {
58+ static_assert (Bits == 32 || Bits == 64 , " Unexpected Bits argument" );
59+ using PHeader = typename std::conditional<Bits == 32 , Elf32_Phdr, Elf64_Phdr>::type;
60+ auto header = get_header_info ();
61+ if (header.is_error ()) {
62+ return std::move (header).unwrap_error ();
63+ }
64+ const auto & header_info = header.unwrap_value ();
65+ // PT_PHDR will occur at most once
66+ // Should be somewhat reliable https://stackoverflow.com/q/61568612/15675011
67+ // It should occur at the beginning but may as well loop just in case
68+ for (unsigned i = 0 ; i < header_info.e_phnum ; i++) {
69+ auto loaded_ph = load_bytes<PHeader>(file, header_info.e_phoff + header_info.e_phentsize * i);
70+ if (loaded_ph.is_error ()) {
71+ return std::move (loaded_ph).unwrap_error ();
72+ }
73+ const PHeader& program_header = loaded_ph.unwrap_value ();
74+ if (byteswap_if_needed (program_header.p_type , is_little_endian) == PT_PHDR) {
75+ return byteswap_if_needed (program_header.p_vaddr , is_little_endian) -
76+ byteswap_if_needed (program_header.p_offset , is_little_endian);
77+ }
78+ }
79+ // Apparently some objects like shared objects can end up missing this header. 0 as a base seems correct.
80+ return 0 ;
81+ };
5782 if (is_64) {
58- return get_module_image_base_from_program_table <64 >();
83+ return impl. operator () <64 >();
5984 } else {
60- return get_module_image_base_from_program_table <32 >();
85+ return impl. operator () <32 >();
6186 }
6287 }
6388
@@ -70,35 +95,36 @@ namespace detail {
7095 }
7196 }
7297
73- template <std::size_t Bits>
74- Result<std::uintptr_t , internal_error> elf::get_module_image_base_from_program_table () {
75- static_assert (Bits == 32 || Bits == 64 , " Unexpected Bits argument" );
76- using Header = typename std::conditional<Bits == 32 , Elf32_Ehdr, Elf64_Ehdr>::type;
77- using PHeader = typename std::conditional<Bits == 32 , Elf32_Phdr, Elf64_Phdr>::type;
78- auto loaded_header = load_bytes<Header>(file, 0 );
79- if (loaded_header.is_error ()) {
80- return std::move (loaded_header).unwrap_error ();
81- }
82- const Header& file_header = loaded_header.unwrap_value ();
83- if (file_header.e_ehsize != sizeof (Header)) {
84- return internal_error (" ELF file header size mismatch" + object_path);
98+ Result<elf::header_info, internal_error> elf::get_header_info () {
99+ if (header) {
100+ return header.unwrap ();
85101 }
86- // PT_PHDR will occur at most once
87- // Should be somewhat reliable https://stackoverflow.com/q/61568612/15675011
88- // It should occur at the beginning but may as well loop just in case
89- for (int i = 0 ; i < file_header.e_phnum ; i++) {
90- auto loaded_ph = load_bytes<PHeader>(file, file_header.e_phoff + file_header.e_phentsize * i);
91- if (loaded_ph.is_error ()) {
92- return std::move (loaded_ph).unwrap_error ();
102+ auto impl = [this ]<std::size_t Bits>() -> Result<header_info, internal_error> {
103+ static_assert (Bits == 32 || Bits == 64 , " Unexpected Bits argument" );
104+ using Header = typename std::conditional<Bits == 32 , Elf32_Ehdr, Elf64_Ehdr>::type;
105+ auto loaded_header = load_bytes<Header>(file, 0 );
106+ if (loaded_header.is_error ()) {
107+ return std::move (loaded_header).unwrap_error ();
93108 }
94- const PHeader& program_header = loaded_ph.unwrap_value ();
95- if (byteswap_if_needed (program_header.p_type , is_little_endian) == PT_PHDR) {
96- return byteswap_if_needed (program_header.p_vaddr , is_little_endian) -
97- byteswap_if_needed (program_header.p_offset , is_little_endian);
109+ const Header& file_header = loaded_header.unwrap_value ();
110+ if (file_header.e_ehsize != sizeof (Header)) {
111+ return internal_error (" ELF file header size mismatch" + object_path);
98112 }
113+ header_info info;
114+ info.e_phoff = file_header.e_phoff ;
115+ info.e_phnum = file_header.e_phnum ;
116+ info.e_phentsize = file_header.e_phentsize ;
117+ info.e_shoff = file_header.e_shoff ;
118+ info.e_shnum = file_header.e_shnum ;
119+ info.e_shentsize = file_header.e_shentsize ;
120+ header = info;
121+ return header.unwrap ();
122+ };
123+ if (is_64) {
124+ return impl.operator ()<64 >();
125+ } else {
126+ return impl.operator ()<32 >();
99127 }
100- // Apparently some objects like shared objects can end up missing this header. 0 as a base seems correct.
101- return 0 ;
102128 }
103129}
104130}
0 commit comments