diff --git a/linker/linker_crt_pad_segment_test.cpp b/linker/linker_crt_pad_segment_test.cpp index 5a219f8ee..c11df50fe 100644 --- a/linker/linker_crt_pad_segment_test.cpp +++ b/linker/linker_crt_pad_segment_test.cpp @@ -72,13 +72,22 @@ bool GetPadSegment(const std::string& elf_path) { }; // anonymous namespace TEST(crt_pad_segment, note_absent) { + if (!page_size_migration_supported()) { + GTEST_SKIP() << "Kernel does not support page size migration"; + } ASSERT_FALSE(GetPadSegment("no_crt_pad_segment.so")); } TEST(crt_pad_segment, note_present_and_enabled) { + if (!page_size_migration_supported()) { + GTEST_SKIP() << "Kernel does not support page size migration"; + } ASSERT_TRUE(GetPadSegment("crt_pad_segment_enabled.so")); } TEST(crt_pad_segment, note_present_and_disabled) { + if (!page_size_migration_supported()) { + GTEST_SKIP() << "Kernel does not support page size migration"; + } ASSERT_FALSE(GetPadSegment("crt_pad_segment_disabled.so")); } diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp index 685ae7082..80f1ad9d4 100644 --- a/linker/linker_phdr.cpp +++ b/linker/linker_phdr.cpp @@ -46,6 +46,8 @@ #include "private/CFIShadow.h" // For kLibraryAlignment #include "private/elf_note.h" +#include + static int GetTargetElfMachine() { #if defined(__arm__) return EM_ARM; @@ -707,8 +709,28 @@ bool ElfReader::ReserveAddressSpace(address_space_params* address_space) { return true; } +/* + * Returns true if the kernel supports page size migration, else false. + */ +bool page_size_migration_supported() { + static bool pgsize_migration_enabled = []() { + std::string enabled; + if (!android::base::ReadFileToString("/sys/kernel/mm/pgsize_migration/enabled", &enabled)) { + return false; + } + return enabled.find("1") != std::string::npos; + }(); + return pgsize_migration_enabled; +} + // Find the ELF note of type NT_ANDROID_TYPE_PAD_SEGMENT and check that the desc value is 1. bool ElfReader::ReadPadSegmentNote() { + if (!page_size_migration_supported()) { + // Don't attempt to read the note, since segment extension isn't + // supported; but return true so that loading can continue normally. + return true; + } + // 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]; diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h index 61242eb4c..aab9018b4 100644 --- a/linker/linker_phdr.h +++ b/linker/linker_phdr.h @@ -154,3 +154,5 @@ void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_co const char* phdr_table_get_interpreter_name(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias); + +bool page_size_migration_supported();