linker: LoadSegments: Factor out MapSegment()
This is a preparatory patch for 16KiB app compat. No functional change
is introduced.
Bug: 339709616
Test: linker-unit-tests
Change-Id: I9ff02cd24fdf83913e55dc62f35ada904f4cb8c5
Signed-off-by: Kalesh Singh <kaleshsingh@google.com>
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index e89acb5..06373ad 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -851,6 +851,33 @@
*p_filesz += extend;
}
+bool ElfReader::MapSegment(size_t seg_idx, size_t len) {
+ const ElfW(Phdr)* phdr = &phdr_table_[seg_idx];
+
+ void* start = reinterpret_cast<void*>(page_start(phdr->p_vaddr + load_bias_));
+
+ // The ELF could be being loaded directly from a zipped APK,
+ // the zip offset must be added to find the segment offset.
+ const ElfW(Addr) offset = file_offset_ + page_start(phdr->p_offset);
+
+ int prot = PFLAGS_TO_PROT(phdr->p_flags);
+
+ void* seg_addr = mmap64(start, len, prot, MAP_FIXED | MAP_PRIVATE, fd_, offset);
+
+ if (seg_addr == MAP_FAILED) {
+ DL_ERR("couldn't map \"%s\" segment %zd: %m", name_.c_str(), seg_idx);
+ return false;
+ }
+
+ // Mark segments as huge page eligible if they meet the requirements
+ if ((phdr->p_flags & PF_X) && phdr->p_align == kPmdSize &&
+ get_transparent_hugepages_supported()) {
+ madvise(seg_addr, len, MADV_HUGEPAGE);
+ }
+
+ return true;
+}
+
bool ElfReader::LoadSegments() {
size_t min_palign = phdr_table_get_minimum_alignment(phdr_table_, phdr_num_);
// Only enforce this on 16 KB systems. Apps may rely on undefined behavior
@@ -917,23 +944,10 @@
add_dlwarning(name_.c_str(), "W+E load segments");
}
- void* seg_addr = mmap64(reinterpret_cast<void*>(seg_page_start),
- file_length,
- prot,
- MAP_FIXED|MAP_PRIVATE,
- fd_,
- file_offset_ + file_page_start);
- if (seg_addr == MAP_FAILED) {
- DL_ERR("couldn't map \"%s\" segment %zd: %m", name_.c_str(), i);
+ // Pass the file_length, since it may have been extended by _extend_load_segment_vma().
+ if (!MapSegment(i, file_length)) {
return false;
}
-
- // Mark segments as huge page eligible if they meet the requirements
- // (executable and PMD aligned).
- if ((phdr->p_flags & PF_X) && phdr->p_align == kPmdSize &&
- get_transparent_hugepages_supported()) {
- madvise(seg_addr, file_length, MADV_HUGEPAGE);
- }
}
// if the segment is writable, and does not end on a page boundary,
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index e865a03..c7320ae 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -68,6 +68,7 @@
[[nodiscard]] bool ReadDynamicSection();
[[nodiscard]] bool ReadPadSegmentNote();
[[nodiscard]] bool ReserveAddressSpace(address_space_params* address_space);
+ [[nodiscard]] bool MapSegment(size_t seg_idx, size_t len);
[[nodiscard]] bool LoadSegments();
[[nodiscard]] bool FindPhdr();
[[nodiscard]] bool FindGnuPropertySection();