summaryrefslogtreecommitdiff
path: root/dex2oat/linker/elf_writer_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'dex2oat/linker/elf_writer_test.cc')
-rw-r--r--dex2oat/linker/elf_writer_test.cc261
1 files changed, 261 insertions, 0 deletions
diff --git a/dex2oat/linker/elf_writer_test.cc b/dex2oat/linker/elf_writer_test.cc
index e1ef575502..e37e41d3b5 100644
--- a/dex2oat/linker/elf_writer_test.cc
+++ b/dex2oat/linker/elf_writer_test.cc
@@ -21,6 +21,7 @@
#include "base/unix_file/fd_file.h"
#include "base/utils.h"
#include "common_compiler_driver_test.h"
+#include "driver/compiler_driver.h"
#include "elf/elf_builder.h"
#include "elf_writer_quick.h"
#include "oat/elf_file.h"
@@ -35,6 +36,50 @@ class ElfWriterTest : public CommonCompilerDriverTest {
void SetUp() override {
ReserveImageSpace();
CommonCompilerTest::SetUp();
+ CreateCompilerDriver();
+ }
+
+ void WriteElf(File* oat_file,
+ const std::vector<uint8_t>& rodata,
+ const std::vector<uint8_t>& text,
+ const std::vector<uint8_t>& data_img_rel_ro,
+ size_t data_img_rel_ro_app_image_offset,
+ size_t bss_size,
+ size_t bss_methods_offset,
+ size_t bss_roots_offset,
+ size_t dex_section_size) {
+ std::unique_ptr<ElfWriter> elf_writer = CreateElfWriterQuick(
+ compiler_driver_->GetCompilerOptions(),
+ oat_file);
+
+ elf_writer->Start();
+ OutputStream* rodata_section = elf_writer->StartRoData();
+
+ elf_writer->PrepareDynamicSection(rodata.size(),
+ text.size(),
+ data_img_rel_ro.size(),
+ data_img_rel_ro_app_image_offset,
+ bss_size,
+ bss_methods_offset,
+ bss_roots_offset,
+ dex_section_size);
+
+ ASSERT_TRUE(rodata_section->WriteFully(rodata.data(), rodata.size()));
+ elf_writer->EndRoData(rodata_section);
+
+ OutputStream* text_section = elf_writer->StartText();
+ ASSERT_TRUE(text_section->WriteFully(text.data(), text.size()));
+ elf_writer->EndText(text_section);
+
+ if (!data_img_rel_ro.empty()) {
+ OutputStream* data_img_rel_ro_section = elf_writer->StartDataImgRelRo();
+ ASSERT_TRUE(data_img_rel_ro_section->WriteFully(data_img_rel_ro.data(),
+ data_img_rel_ro.size()));
+ elf_writer->EndDataImgRelRo(data_img_rel_ro_section);
+ }
+
+ elf_writer->WriteDynamicSection();
+ ASSERT_TRUE(elf_writer->End());
}
};
@@ -137,5 +182,221 @@ TEST_F(ElfWriterTest, CheckBuildIdPresent) {
}
}
+// Check that dynamic sections (.dynamic, .dynsym, .dynstr, .hash) in an oat file are formed
+// correctly so that dynamic symbols can be successfully looked up.
+TEST_F(ElfWriterTest, CheckDynamicSection) {
+ // This function generates an oat file with the specified oat data sizes and offsets and
+ // verifies it:
+ // * Checks that the file can be loaded by the ELF loader.
+ // * Checks that the expected dynamic symbols exist and point to the corresponding data
+ // in the loaded file.
+ // * Checks the alignment of the oat data.
+ // The function returns the number of dynamic symbols (excluding "lastword" ones) in the
+ // generated oat file.
+ auto verify = [this](size_t rodata_size,
+ size_t text_size,
+ size_t data_img_rel_ro_size,
+ size_t data_img_rel_ro_app_image_offset,
+ size_t bss_size,
+ size_t bss_methods_offset,
+ size_t bss_roots_offset,
+ size_t dex_section_size,
+ /*out*/ size_t *number_of_dynamic_symbols) {
+ SCOPED_TRACE(testing::Message() << "rodata_size: " << rodata_size
+ << ", text_size: " << text_size
+ << ", data_img_rel_ro_size: " << data_img_rel_ro_size
+ << ", data_img_rel_ro_app_image_offset: " << data_img_rel_ro_app_image_offset
+ << ", bss_size: " << bss_size
+ << ", bss_methods_offset: " << bss_methods_offset
+ << ", bss_roots_offset: " << bss_roots_offset
+ << ", dex_section_size: " << dex_section_size);
+
+ *number_of_dynamic_symbols = 1; // "oatdata".
+ std::vector<uint8_t> rodata(rodata_size, 0xAA);
+ std::vector<uint8_t> text(text_size, 0xBB);
+ std::vector<uint8_t> data_img_rel_ro(data_img_rel_ro_app_image_offset, 0xCC);
+ size_t data_img_rel_ro_app_image_size = data_img_rel_ro_size - data_img_rel_ro_app_image_offset;
+ data_img_rel_ro.insert(data_img_rel_ro.cend(), data_img_rel_ro_app_image_size, 0xDD);
+
+ ScratchFile tmp_base, tmp_oat(tmp_base, ".oat");
+ WriteElf(tmp_oat.GetFile(),
+ rodata,
+ text,
+ data_img_rel_ro,
+ data_img_rel_ro_app_image_offset,
+ bss_size,
+ bss_methods_offset,
+ bss_roots_offset,
+ dex_section_size);
+
+ std::string error_msg;
+ std::unique_ptr<ElfFile> ef(ElfFile::Open(tmp_oat.GetFile(),
+ /*writable=*/ false,
+ /*program_header_only=*/ true,
+ /*low_4gb=*/ false,
+ &error_msg));
+ ASSERT_NE(ef.get(), nullptr) << error_msg;
+ ASSERT_TRUE(ef->Load(tmp_oat.GetFile(),
+ /*executable=*/false,
+ /*low_4gb=*/false,
+ /*reservation=*/nullptr,
+ &error_msg)) << error_msg;
+
+ const uint8_t* oatdata_ptr = ef->FindDynamicSymbolAddress("oatdata");
+ ASSERT_NE(oatdata_ptr, nullptr);
+ EXPECT_EQ(memcmp(oatdata_ptr, rodata.data(), rodata.size()), 0);
+
+ size_t page_size = GetPageSizeSlow();
+ size_t elf_word_size = ef->Is64Bit() ? sizeof(ElfTypes64::Word) : sizeof(ElfTypes32::Word);
+
+ if (text_size != 0u) {
+ *number_of_dynamic_symbols += 1;
+ const uint8_t* text_ptr = ef->FindDynamicSymbolAddress("oatexec");
+ ASSERT_NE(text_ptr, nullptr);
+ ASSERT_TRUE(IsAlignedParam(text_ptr, page_size));
+ EXPECT_EQ(memcmp(text_ptr, text.data(), text.size()), 0);
+
+ const uint8_t* oatlastword_ptr = ef->FindDynamicSymbolAddress("oatlastword");
+ ASSERT_NE(oatlastword_ptr, nullptr);
+ EXPECT_EQ(static_cast<size_t>(oatlastword_ptr - text_ptr), text_size - elf_word_size);
+ } else if (rodata_size != 0u) {
+ const uint8_t* oatlastword_ptr = ef->FindDynamicSymbolAddress("oatlastword");
+ ASSERT_NE(oatlastword_ptr, nullptr);
+ EXPECT_EQ(static_cast<size_t>(oatlastword_ptr - oatdata_ptr), rodata_size - elf_word_size);
+ }
+
+ if (data_img_rel_ro_size != 0u) {
+ *number_of_dynamic_symbols += 1;
+ const uint8_t* oatdataimgrelro_ptr = ef->FindDynamicSymbolAddress("oatdataimgrelro");
+ ASSERT_NE(oatdataimgrelro_ptr, nullptr);
+ ASSERT_TRUE(IsAlignedParam(oatdataimgrelro_ptr, page_size));
+ EXPECT_EQ(memcmp(oatdataimgrelro_ptr, data_img_rel_ro.data(), data_img_rel_ro.size()), 0);
+
+ const uint8_t* oatdataimgrelrolastword_ptr =
+ ef->FindDynamicSymbolAddress("oatdataimgrelrolastword");
+ ASSERT_NE(oatdataimgrelrolastword_ptr, nullptr);
+ EXPECT_EQ(static_cast<size_t>(oatdataimgrelrolastword_ptr - oatdataimgrelro_ptr),
+ data_img_rel_ro_size - elf_word_size);
+
+ if (data_img_rel_ro_app_image_offset != data_img_rel_ro_size) {
+ *number_of_dynamic_symbols += 1;
+ const uint8_t* oatdataimgrelroappimage_ptr =
+ ef->FindDynamicSymbolAddress("oatdataimgrelroappimage");
+ ASSERT_NE(oatdataimgrelroappimage_ptr, nullptr);
+ EXPECT_EQ(static_cast<size_t>(oatdataimgrelroappimage_ptr - oatdataimgrelro_ptr),
+ data_img_rel_ro_app_image_offset);
+ }
+
+ if (bss_size != 0u) {
+ *number_of_dynamic_symbols += 1;
+ const uint8_t* bss_ptr = ef->FindDynamicSymbolAddress("oatbss");
+ ASSERT_NE(bss_ptr, nullptr);
+ ASSERT_TRUE(IsAlignedParam(bss_ptr, page_size));
+
+ if (bss_methods_offset != bss_roots_offset) {
+ *number_of_dynamic_symbols += 1;
+ const uint8_t* oatbssmethods_ptr = ef->FindDynamicSymbolAddress("oatbssmethods");
+ ASSERT_NE(oatbssmethods_ptr, nullptr);
+ EXPECT_EQ(static_cast<size_t>(oatbssmethods_ptr - bss_ptr), bss_methods_offset);
+ }
+
+ if (bss_roots_offset != bss_size) {
+ *number_of_dynamic_symbols += 1;
+ const uint8_t* oatbssroots_ptr = ef->FindDynamicSymbolAddress("oatbssroots");
+ ASSERT_NE(oatbssroots_ptr, nullptr);
+ EXPECT_EQ(static_cast<size_t>(oatbssroots_ptr - bss_ptr), bss_roots_offset);
+ }
+
+ const uint8_t* oatbsslastword_ptr = ef->FindDynamicSymbolAddress("oatbsslastword");
+ ASSERT_NE(oatbsslastword_ptr, nullptr);
+ EXPECT_EQ(static_cast<size_t>(oatbsslastword_ptr - bss_ptr), bss_size - elf_word_size);
+ }
+ }
+
+ if (dex_section_size != 0u) {
+ *number_of_dynamic_symbols += 1;
+ const uint8_t* dex_ptr = ef->FindDynamicSymbolAddress("oatdex");
+ ASSERT_NE(dex_ptr, nullptr);
+ ASSERT_TRUE(IsAlignedParam(dex_ptr, page_size));
+ const uint8_t* oatdexlastword_ptr = ef->FindDynamicSymbolAddress("oatdexlastword");
+ EXPECT_EQ(static_cast<size_t>(oatdexlastword_ptr - dex_ptr),
+ dex_section_size - elf_word_size);
+ }
+ };
+
+ // If a symbol requires some other ones (e.g. kBssMethods requires kBss),
+ // it should be listed after them.
+ enum class Symbol {
+ kRodata,
+ kText,
+ kDataImgRelRo,
+ kDataImgRelRoAppImage,
+ kBss,
+ kBssMethods,
+ kBssRoots,
+ kDex,
+ kLast = kDex
+ };
+
+ constexpr size_t kNumberOfSymbols = static_cast<size_t>(Symbol::kLast) + 1;
+
+ // Use an unaligned section size to verify that ElfWriter properly aligns sections in this case.
+ // We can use an arbitrary value that is greater than or equal to an ElfWord (4 bytes).
+ constexpr size_t kSectionSize = 127u;
+ // Offset in .data.img.rel.ro section from its beginning. We can use any value in the range
+ // [0, kSectionSize).
+ constexpr size_t kDataImgRelRoAppImageOffset = kSectionSize / 2;
+ // Offsets in .bss from its beginning. We can use any value in the range [0, kSectionSize),
+ // kBssMethodsOffset should be less than or equal to kBssRootsOffset.
+ constexpr size_t kBssMethodsOffset = kSectionSize / 3;
+ constexpr size_t kBssRootsOffset = 2 * kBssMethodsOffset;
+
+ auto exists = [](Symbol symbol, const std::bitset<kNumberOfSymbols> &symbols) {
+ return symbols.test(static_cast<size_t>(symbol));
+ };
+
+ auto get_size = [&](Symbol symbol, const std::bitset<kNumberOfSymbols> &symbols) -> size_t {
+ return exists(symbol, symbols) ? kSectionSize : 0;
+ };
+
+ std::bitset<kNumberOfSymbols> symbols;
+ symbols.set();
+
+ // Check cases that lead to a different number of dynamic symbols in an oat file.
+ // We start with the case where all symbols exist (corresponding to the bitset 11111111)
+ // and continue to the case where only "oatdata" exists:
+ // 11111111 - all symbols exist.
+ // 01111111 - "oatdex" doesn't exist (least significant bit corresponds to "oatdata").
+ // 00111111 - "oatdex" and "oatbss" don't exist.
+ // ...
+ // 00000001 - only "oatdata" exists.
+ while (symbols.any()) {
+ DCHECK_IMPLIES(exists(Symbol::kDataImgRelRoAppImage, symbols),
+ exists(Symbol::kDataImgRelRo, symbols));
+ DCHECK_IMPLIES(exists(Symbol::kBssMethods, symbols), exists(Symbol::kBss, symbols));
+ DCHECK_IMPLIES(exists(Symbol::kBssRoots, symbols), exists(Symbol::kBss, symbols));
+ DCHECK_IMPLIES(exists(Symbol::kBssRoots, symbols), exists(Symbol::kBssMethods, symbols));
+
+ size_t data_img_rel_ro_size = get_size(Symbol::kDataImgRelRo, symbols);
+ size_t bss_size = get_size(Symbol::kBss, symbols);
+ size_t number_of_dynamic_symbols = 0;
+ verify(get_size(Symbol::kRodata, symbols),
+ get_size(Symbol::kText, symbols),
+ data_img_rel_ro_size,
+ exists(Symbol::kDataImgRelRoAppImage, symbols)
+ ? kDataImgRelRoAppImageOffset
+ : data_img_rel_ro_size,
+ bss_size,
+ exists(Symbol::kBssMethods, symbols) ? kBssMethodsOffset : bss_size,
+ exists(Symbol::kBssRoots, symbols) ? kBssRootsOffset : bss_size,
+ get_size(Symbol::kDex, symbols),
+ &number_of_dynamic_symbols);
+ EXPECT_EQ(number_of_dynamic_symbols, symbols.count())
+ << "number_of_dynamic_symbols: " << number_of_dynamic_symbols
+ << ", symbols: " << symbols;
+ symbols >>= 1;
+ }
+}
+
} // namespace linker
} // namespace art