Merge "Revert "linker: map large portion of ELF file to read its fragments"" into main
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index b0675c1..ff3d498 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -221,22 +221,17 @@
}
bool ElfReader::ReadElfHeader() {
- size_t map_size = file_size_ - file_offset_;
- if (map_size < sizeof(header_)) {
+ ssize_t rc = TEMP_FAILURE_RETRY(pread64(fd_, &header_, sizeof(header_), file_offset_));
+ if (rc < 0) {
+ DL_ERR("can't read file \"%s\": %s", name_.c_str(), strerror(errno));
+ return false;
+ }
+
+ if (rc != sizeof(header_)) {
DL_ERR("\"%s\" is too small to be an ELF executable: only found %zd bytes", name_.c_str(),
- map_size);
+ static_cast<size_t>(rc));
return false;
}
-
- // Map at most 1MiB which should cover most cases
- map_size = std::min(map_size, static_cast<size_t>(1 * 1024 * 1024));
-
- if (!file_fragment_.Map(fd_, file_offset_, 0, map_size)) {
- DL_ERR("\"%s\" header mmap failed: %m", name_.c_str());
- return false;
- }
-
- header_ = *static_cast<ElfW(Ehdr)*>(file_fragment_.data());
return true;
}
@@ -345,24 +340,6 @@
((offset % alignment) == 0);
}
-void* ElfReader::MapData(MappedFileFragment* fragment, off64_t offset, off64_t size) {
- off64_t end;
- CHECK(safe_add(&end, offset, size));
-
- // If the data is already mapped just return it
- if (static_cast<off64_t>(file_fragment_.size()) >= end) {
- return static_cast<char*>(file_fragment_.data()) + offset;
- }
- // Use the passed-in fragment if area is not mapped. We can't remap the original fragment
- // because that invalidates all previous pointers if the file is remapped to a different
- // virtual address. A local variable can't be used in place of the passed-in fragment because
- // the area would be unmapped as soon as the local object goes out of scope.
- if (fragment->Map(fd_, file_offset_, offset, size)) {
- return fragment->data();
- }
- return nullptr;
-}
-
// Loads the program header table from an ELF file into a read-only private
// anonymous mmap-ed block.
bool ElfReader::ReadProgramHeaders() {
@@ -385,13 +362,12 @@
return false;
}
- void* phdr_data = MapData(&phdr_fragment_, header_.e_phoff, size);
- if (phdr_data == nullptr) {
+ if (!phdr_fragment_.Map(fd_, file_offset_, header_.e_phoff, size)) {
DL_ERR("\"%s\" phdr mmap failed: %m", name_.c_str());
return false;
}
- phdr_table_ = static_cast<ElfW(Phdr)*>(phdr_data);
+ phdr_table_ = static_cast<ElfW(Phdr)*>(phdr_fragment_.data());
return true;
}
@@ -412,13 +388,12 @@
return false;
}
- void* shdr_data = MapData(&shdr_fragment_, header_.e_shoff, size);
- if (shdr_data == nullptr) {
+ if (!shdr_fragment_.Map(fd_, file_offset_, header_.e_shoff, size)) {
DL_ERR("\"%s\" shdr mmap failed: %m", name_.c_str());
return false;
}
- shdr_table_ = static_cast<const ElfW(Shdr)*>(shdr_data);
+ shdr_table_ = static_cast<const ElfW(Shdr)*>(shdr_fragment_.data());
return true;
}
@@ -506,13 +481,12 @@
return false;
}
- void* dynamic_data = MapData(&dynamic_fragment_, dynamic_shdr->sh_offset, dynamic_shdr->sh_size);
- if (dynamic_data == nullptr) {
+ if (!dynamic_fragment_.Map(fd_, file_offset_, dynamic_shdr->sh_offset, dynamic_shdr->sh_size)) {
DL_ERR("\"%s\" dynamic section mmap failed: %m", name_.c_str());
return false;
}
- dynamic_ = static_cast<const ElfW(Dyn)*>(dynamic_data);
+ dynamic_ = static_cast<const ElfW(Dyn)*>(dynamic_fragment_.data());
if (!CheckFileRange(strtab_shdr->sh_offset, strtab_shdr->sh_size, alignof(const char))) {
DL_ERR_AND_LOG("\"%s\" has invalid offset/size of the .strtab section linked from .dynamic section",
@@ -520,14 +494,13 @@
return false;
}
- void* strtab_data = MapData(&strtab_fragment_, strtab_shdr->sh_offset, strtab_shdr->sh_size);
- if (strtab_data == nullptr) {
+ if (!strtab_fragment_.Map(fd_, file_offset_, strtab_shdr->sh_offset, strtab_shdr->sh_size)) {
DL_ERR("\"%s\" strtab section mmap failed: %m", name_.c_str());
return false;
}
- strtab_ = static_cast<const char*>(strtab_data);
- strtab_size_ = strtab_shdr->sh_size;
+ strtab_ = static_cast<const char*>(strtab_fragment_.data());
+ strtab_size_ = strtab_fragment_.size();
return true;
}
@@ -783,8 +756,7 @@
// note_fragment is scoped to within the loop so that there is
// at most 1 PT_NOTE mapped at anytime during this search.
MappedFileFragment note_fragment;
- void* note_data = MapData(¬e_fragment, phdr->p_offset, phdr->p_memsz);
- if (note_data == nullptr) {
+ if (!note_fragment.Map(fd_, file_offset_, phdr->p_offset, phdr->p_memsz)) {
DL_ERR("\"%s\": PT_NOTE mmap(nullptr, %p, PROT_READ, MAP_PRIVATE, %d, %p) failed: %m",
name_.c_str(), reinterpret_cast<void*>(phdr->p_memsz), fd_,
reinterpret_cast<void*>(page_start(file_offset_ + phdr->p_offset)));
@@ -794,7 +766,7 @@
const ElfW(Nhdr)* note_hdr = nullptr;
const char* note_desc = nullptr;
if (!__get_elf_note(NT_ANDROID_TYPE_PAD_SEGMENT, "Android",
- reinterpret_cast<ElfW(Addr)>(note_data),
+ reinterpret_cast<ElfW(Addr)>(note_fragment.data()),
phdr, ¬e_hdr, ¬e_desc)) {
continue;
}
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index e7aae6e..aab9018 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -73,7 +73,6 @@
[[nodiscard]] bool FindGnuPropertySection();
[[nodiscard]] bool CheckPhdr(ElfW(Addr));
[[nodiscard]] bool CheckFileRange(ElfW(Addr) offset, size_t size, size_t alignment);
- [[nodiscard]] void* MapData(MappedFileFragment* fragment, off64_t offset, off64_t size);
bool did_read_;
bool did_load_;
@@ -82,8 +81,6 @@
off64_t file_offset_;
off64_t file_size_;
- MappedFileFragment file_fragment_;
-
ElfW(Ehdr) header_;
size_t phdr_num_;