Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 7ceba7b

Browse files
Treehugger RobotGerrit Code Review
authored andcommitted
Merge changes Id8264654,I7b25151a into main
* changes: linker: map the entire ELF file if address space is 64bit linker: map large portion of ELF file to read its fragments
2 parents 2f50bd8 + 8eebd02 commit 7ceba7b

File tree

2 files changed

+50
-17
lines changed

2 files changed

+50
-17
lines changed

linker/linker_phdr.cpp

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -221,17 +221,24 @@ const char* ElfReader::get_string(ElfW(Word) index) const {
221221
}
222222

223223
bool ElfReader::ReadElfHeader() {
224-
ssize_t rc = TEMP_FAILURE_RETRY(pread64(fd_, &header_, sizeof(header_), file_offset_));
225-
if (rc < 0) {
226-
DL_ERR("can't read file \"%s\": %s", name_.c_str(), strerror(errno));
224+
size_t map_size = file_size_ - file_offset_;
225+
if (map_size < sizeof(header_)) {
226+
DL_ERR("\"%s\" is too small to be an ELF executable: only found %zd bytes", name_.c_str(),
227+
map_size);
227228
return false;
228229
}
229230

230-
if (rc != sizeof(header_)) {
231-
DL_ERR("\"%s\" is too small to be an ELF executable: only found %zd bytes", name_.c_str(),
232-
static_cast<size_t>(rc));
231+
#if !defined(__LP64__)
232+
// Map at most 1MiB which should cover most cases
233+
map_size = std::min(map_size, static_cast<size_t>(1 * 1024 * 1024));
234+
#endif
235+
236+
if (!file_fragment_.Map(fd_, file_offset_, 0, map_size)) {
237+
DL_ERR("\"%s\" header mmap failed: %s", name_.c_str(), strerror(errno));
233238
return false;
234239
}
240+
241+
header_ = *static_cast<ElfW(Ehdr)*>(file_fragment_.data());
235242
return true;
236243
}
237244

@@ -340,6 +347,24 @@ bool ElfReader::CheckFileRange(ElfW(Addr) offset, size_t size, size_t alignment)
340347
((offset % alignment) == 0);
341348
}
342349

350+
void* ElfReader::MapData(MappedFileFragment* fragment, off64_t offs, off64_t size) {
351+
off64_t end;
352+
CHECK(safe_add(&end, offs, size));
353+
354+
// If the data is already mapped just return it
355+
if (static_cast<off64_t>(file_fragment_.size()) >= end) {
356+
return static_cast<char*>(file_fragment_.data()) + offs;
357+
}
358+
// Use the passed-in fragment if area is not mapped. We can't remap the original fragment
359+
// because that invalidates all previous pointers if the file is remapped to a different
360+
// virtual address. A local variable can't be used in place of the passed-in fragment because
361+
// the area would be unmapped as soon as the local object goes out of scope.
362+
if (fragment->Map(fd_, file_offset_, offs, size)) {
363+
return fragment->data();
364+
}
365+
return nullptr;
366+
}
367+
343368
// Loads the program header table from an ELF file into a read-only private
344369
// anonymous mmap-ed block.
345370
bool ElfReader::ReadProgramHeaders() {
@@ -362,12 +387,13 @@ bool ElfReader::ReadProgramHeaders() {
362387
return false;
363388
}
364389

365-
if (!phdr_fragment_.Map(fd_, file_offset_, header_.e_phoff, size)) {
390+
void* phdr_data = MapData(&phdr_fragment_, header_.e_phoff, size);
391+
if (phdr_data == nullptr) {
366392
DL_ERR("\"%s\" phdr mmap failed: %s", name_.c_str(), strerror(errno));
367393
return false;
368394
}
369395

370-
phdr_table_ = static_cast<ElfW(Phdr)*>(phdr_fragment_.data());
396+
phdr_table_ = static_cast<ElfW(Phdr)*>(phdr_data);
371397
return true;
372398
}
373399

@@ -388,12 +414,13 @@ bool ElfReader::ReadSectionHeaders() {
388414
return false;
389415
}
390416

391-
if (!shdr_fragment_.Map(fd_, file_offset_, header_.e_shoff, size)) {
417+
void* shdr_data = MapData(&shdr_fragment_, header_.e_shoff, size);
418+
if (shdr_data == nullptr) {
392419
DL_ERR("\"%s\" shdr mmap failed: %s", name_.c_str(), strerror(errno));
393420
return false;
394421
}
395422

396-
shdr_table_ = static_cast<const ElfW(Shdr)*>(shdr_fragment_.data());
423+
shdr_table_ = static_cast<const ElfW(Shdr)*>(shdr_data);
397424
return true;
398425
}
399426

@@ -481,26 +508,28 @@ bool ElfReader::ReadDynamicSection() {
481508
return false;
482509
}
483510

484-
if (!dynamic_fragment_.Map(fd_, file_offset_, dynamic_shdr->sh_offset, dynamic_shdr->sh_size)) {
511+
void* dynamic_data = MapData(&dynamic_fragment_, dynamic_shdr->sh_offset, dynamic_shdr->sh_size);
512+
if (dynamic_data == nullptr) {
485513
DL_ERR("\"%s\" dynamic section mmap failed: %s", name_.c_str(), strerror(errno));
486514
return false;
487515
}
488516

489-
dynamic_ = static_cast<const ElfW(Dyn)*>(dynamic_fragment_.data());
517+
dynamic_ = static_cast<const ElfW(Dyn)*>(dynamic_data);
490518

491519
if (!CheckFileRange(strtab_shdr->sh_offset, strtab_shdr->sh_size, alignof(const char))) {
492520
DL_ERR_AND_LOG("\"%s\" has invalid offset/size of the .strtab section linked from .dynamic section",
493521
name_.c_str());
494522
return false;
495523
}
496524

497-
if (!strtab_fragment_.Map(fd_, file_offset_, strtab_shdr->sh_offset, strtab_shdr->sh_size)) {
525+
void* strtab_data = MapData(&strtab_fragment_, strtab_shdr->sh_offset, strtab_shdr->sh_size);
526+
if (strtab_data == nullptr) {
498527
DL_ERR("\"%s\" strtab section mmap failed: %s", name_.c_str(), strerror(errno));
499528
return false;
500529
}
501530

502-
strtab_ = static_cast<const char*>(strtab_fragment_.data());
503-
strtab_size_ = strtab_fragment_.size();
531+
strtab_ = static_cast<const char*>(strtab_data);
532+
strtab_size_ = strtab_shdr->sh_size;
504533
return true;
505534
}
506535

@@ -756,7 +785,8 @@ bool ElfReader::ReadPadSegmentNote() {
756785
// note_fragment is scoped to within the loop so that there is
757786
// at most 1 PT_NOTE mapped at anytime during this search.
758787
MappedFileFragment note_fragment;
759-
if (!note_fragment.Map(fd_, file_offset_, phdr->p_offset, phdr->p_memsz)) {
788+
void* note_data = MapData(&note_fragment, phdr->p_offset, phdr->p_memsz);
789+
if (note_data == nullptr) {
760790
DL_ERR("\"%s\": PT_NOTE mmap(nullptr, %p, PROT_READ, MAP_PRIVATE, %d, %p) failed: %m",
761791
name_.c_str(), reinterpret_cast<void*>(phdr->p_memsz), fd_,
762792
reinterpret_cast<void*>(page_start(file_offset_ + phdr->p_offset)));
@@ -766,7 +796,7 @@ bool ElfReader::ReadPadSegmentNote() {
766796
const ElfW(Nhdr)* note_hdr = nullptr;
767797
const char* note_desc = nullptr;
768798
if (!__get_elf_note(NT_ANDROID_TYPE_PAD_SEGMENT, "Android",
769-
reinterpret_cast<ElfW(Addr)>(note_fragment.data()),
799+
reinterpret_cast<ElfW(Addr)>(note_data),
770800
phdr, &note_hdr, &note_desc)) {
771801
continue;
772802
}

linker/linker_phdr.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class ElfReader {
7373
[[nodiscard]] bool FindGnuPropertySection();
7474
[[nodiscard]] bool CheckPhdr(ElfW(Addr));
7575
[[nodiscard]] bool CheckFileRange(ElfW(Addr) offset, size_t size, size_t alignment);
76+
[[nodiscard]] void* MapData(MappedFileFragment* fragment, off64_t offs, off64_t size);
7677

7778
bool did_read_;
7879
bool did_load_;
@@ -81,6 +82,8 @@ class ElfReader {
8182
off64_t file_offset_;
8283
off64_t file_size_;
8384

85+
MappedFileFragment file_fragment_;
86+
8487
ElfW(Ehdr) header_;
8588
size_t phdr_num_;
8689

0 commit comments

Comments
 (0)