bionic: Introduce ElfReader::ReadPadSegmentNote()

ReadPadSegmentNote() finds the elf note of type
NT_ANDROID_TYPE_PAD_SEGMENT and checks that the desc value
is 1, to decided whether the LOAD segment mappings should
be extended (padded) to avoid gaps.

Cache the result of this operation in ElfReader and soinfo
for use in the subsequent patch which handles the extension
of the segment mappings.

Test: atest -c linker-unit-tests [Later patch]
Test: m && launch_cvd
Bug: 316403210
Change-Id: I32c05cce741d221c3f92835ea09d932c40bdf8b1
Signed-off-by: Kalesh Singh <kaleshsingh@google.com>
This commit is contained in:
Kalesh Singh 2024-01-31 20:23:39 -08:00
parent f0050fb015
commit 377f0b9138
4 changed files with 58 additions and 1 deletions

View file

@ -639,6 +639,7 @@ class LoadTask {
si_->phdr = elf_reader.loaded_phdr();
si_->set_gap_start(elf_reader.gap_start());
si_->set_gap_size(elf_reader.gap_size());
si_->set_should_pad_segments(elf_reader.should_pad_segments());
return true;
}

View file

@ -42,7 +42,9 @@
#include "linker_debug.h"
#include "linker_utils.h"
#include "private/bionic_asm_note.h"
#include "private/CFIShadow.h" // For kLibraryAlignment
#include "private/elf_note.h"
static int GetTargetElfMachine() {
#if defined(__arm__)
@ -163,7 +165,8 @@ bool ElfReader::Read(const char* name, int fd, off64_t file_offset, off64_t file
VerifyElfHeader() &&
ReadProgramHeaders() &&
ReadSectionHeaders() &&
ReadDynamicSection()) {
ReadDynamicSection() &&
ReadPadSegmentNote()) {
did_read_ = true;
}
@ -694,6 +697,46 @@ bool ElfReader::ReserveAddressSpace(address_space_params* address_space) {
return true;
}
// Find the ELF note of type NT_ANDROID_TYPE_PAD_SEGMENT and check that the desc value is 1.
bool ElfReader::ReadPadSegmentNote() {
// The ELF can have multiple PT_NOTE's, check them all
for (size_t i = 0; i < phdr_num_; ++i) {
const ElfW(Phdr)* phdr = &phdr_table_[i];
if (phdr->p_type != PT_NOTE) {
continue;
}
// 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;
if (!note_fragment.Map(fd_, file_offset_, phdr->p_offset, phdr->p_memsz)) {
DL_ERR("\"%s\" note mmap failed: %s", name_.c_str(), strerror(errno));
return false;
}
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_fragment.data()),
phdr, &note_hdr, &note_desc)) {
continue;
}
if (note_hdr->n_descsz != sizeof(ElfW(Word))) {
DL_ERR("\"%s\" NT_ANDROID_TYPE_PAD_SEGMENT note has unexpected n_descsz: %u",
name_.c_str(), reinterpret_cast<unsigned int>(note_hdr->n_descsz));
return false;
}
// 1 == enabled, 0 == disabled
should_pad_segments_ = *reinterpret_cast<const ElfW(Word)*>(note_desc) == 1;
return true;
}
return true;
}
bool ElfReader::LoadSegments() {
for (size_t i = 0; i < phdr_num_; ++i) {
const ElfW(Phdr)* phdr = &phdr_table_[i];

View file

@ -58,6 +58,7 @@ class ElfReader {
const char* get_string(ElfW(Word) index) const;
bool is_mapped_by_caller() const { return mapped_by_caller_; }
ElfW(Addr) entry_point() const { return header_.e_entry + load_bias_; }
bool should_pad_segments() const { return should_pad_segments_; }
private:
bool ReadElfHeader();
@ -65,6 +66,7 @@ class ElfReader {
bool ReadProgramHeaders();
bool ReadSectionHeaders();
bool ReadDynamicSection();
bool ReadPadSegmentNote();
bool ReserveAddressSpace(address_space_params* address_space);
bool LoadSegments();
bool FindPhdr();
@ -113,6 +115,9 @@ class ElfReader {
// Is map owned by the caller
bool mapped_by_caller_;
// Pad gaps between segments when memory mapping?
bool should_pad_segments_ = false;
// Only used by AArch64 at the moment.
GnuPropertySection note_gnu_property_ __unused;
};

View file

@ -364,6 +364,11 @@ struct soinfo {
bool memtag_heap() const { return memtag_dynamic_entries()->memtag_heap; }
bool memtag_stack() const { return memtag_dynamic_entries()->memtag_stack; }
void set_should_pad_segments(bool should_pad_segments) {
should_pad_segments_ = should_pad_segments;
}
bool should_pad_segments() const { return should_pad_segments_; }
private:
bool is_image_linked() const;
void set_image_linked();
@ -449,6 +454,9 @@ struct soinfo {
// version >= 7
memtag_dynamic_entries_t memtag_dynamic_entries_;
// Pad gaps between segments when memory mapping?
bool should_pad_segments_ = false;
};
// This function is used by dlvsym() to calculate hash of sym_ver