• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <gelf.h>
18 #include <libelf.h>
19 #include <sys/mman.h>  // For the PROT_NONE constant.
20 
21 #include <cstdint>
22 
23 #include "android-base/scopeguard.h"
24 #include "base/file_utils.h"
25 #include "base/mem_map.h"
26 #include "base/unix_file/fd_file.h"
27 #include "base/utils.h"
28 #include "common_compiler_driver_test.h"
29 #include "driver/compiler_driver.h"
30 #include "elf/elf_builder.h"
31 #include "elf_writer_quick.h"
32 #include "oat/elf_file.h"
33 #include "oat/elf_file_impl.h"
34 #include "oat/oat.h"
35 
36 namespace art {
37 namespace linker {
38 
39 class ElfWriterTest : public CommonCompilerDriverTest {
40  protected:
SetUp()41   void SetUp() override {
42     ReserveImageSpace();
43     CommonCompilerTest::SetUp();
44     CreateCompilerDriver();
45   }
46 
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)47   void WriteElf(File* oat_file,
48                 const std::vector<uint8_t>& rodata,
49                 const std::vector<uint8_t>& text,
50                 const std::vector<uint8_t>& data_img_rel_ro,
51                 size_t data_img_rel_ro_app_image_offset,
52                 size_t bss_size,
53                 size_t bss_methods_offset,
54                 size_t bss_roots_offset,
55                 size_t dex_section_size) {
56     std::unique_ptr<ElfWriter> elf_writer = CreateElfWriterQuick(
57       compiler_driver_->GetCompilerOptions(),
58       oat_file);
59 
60     elf_writer->Start();
61     OutputStream* rodata_section = elf_writer->StartRoData();
62 
63     elf_writer->PrepareDynamicSection(rodata.size(),
64                                       text.size(),
65                                       data_img_rel_ro.size(),
66                                       data_img_rel_ro_app_image_offset,
67                                       bss_size,
68                                       bss_methods_offset,
69                                       bss_roots_offset,
70                                       dex_section_size);
71 
72     ASSERT_TRUE(rodata_section->WriteFully(rodata.data(), rodata.size()));
73     elf_writer->EndRoData(rodata_section);
74 
75     OutputStream* text_section = elf_writer->StartText();
76     ASSERT_TRUE(text_section->WriteFully(text.data(), text.size()));
77     elf_writer->EndText(text_section);
78 
79     if (!data_img_rel_ro.empty()) {
80       OutputStream* data_img_rel_ro_section = elf_writer->StartDataImgRelRo();
81       ASSERT_TRUE(data_img_rel_ro_section->WriteFully(data_img_rel_ro.data(),
82           data_img_rel_ro.size()));
83       elf_writer->EndDataImgRelRo(data_img_rel_ro_section);
84     }
85 
86     elf_writer->WriteDynamicSection();
87     ASSERT_TRUE(elf_writer->End());
88   }
89 };
90 
FindSymbolAddress(File * file,const char * symbol_name,uint8_t ** addr)91 static void FindSymbolAddress(File* file, const char* symbol_name, /*out*/ uint8_t** addr) {
92   ASSERT_NE(elf_version(EV_CURRENT), EV_NONE) << "libelf initialization failed: " << elf_errmsg(-1);
93 
94   Elf* elf = elf_begin(file->Fd(), ELF_C_READ, /*ref=*/nullptr);
95   ASSERT_NE(elf, nullptr) << elf_errmsg(-1);
96   auto elf_cleanup = android::base::make_scope_guard([&]() { elf_end(elf); });
97 
98   Elf_Scn* dyn_scn = nullptr;
99   GElf_Shdr scn_hdr;
100   while ((dyn_scn = elf_nextscn(elf, dyn_scn)) != nullptr) {
101     ASSERT_EQ(gelf_getshdr(dyn_scn, &scn_hdr), &scn_hdr) << elf_errmsg(-1);
102     if (scn_hdr.sh_type == SHT_DYNSYM) {
103       break;
104     }
105   }
106   ASSERT_NE(dyn_scn, nullptr) << "Section SHT_DYNSYM not found";
107 
108   Elf_Data* data = elf_getdata(dyn_scn, /*data=*/nullptr);
109 
110   // Iterate through dynamic section entries.
111   for (int i = 0; i < scn_hdr.sh_size / scn_hdr.sh_entsize; i++) {
112     GElf_Sym sym;
113     ASSERT_EQ(gelf_getsym(data, i, &sym), &sym) << elf_errmsg(-1);
114     const char* name = elf_strptr(elf, scn_hdr.sh_link, sym.st_name);
115     if (strcmp(name, symbol_name) == 0) {
116       *addr = reinterpret_cast<uint8_t*>(sym.st_value);
117       break;
118     }
119   }
120 
121   ASSERT_NE(*addr, nullptr) << "Symbol " << symbol_name << "not found";
122 }
123 
TEST_F(ElfWriterTest,dlsym)124 TEST_F(ElfWriterTest, dlsym) {
125   std::string elf_location = GetCoreOatLocation();
126   std::string elf_filename = GetSystemImageFilename(elf_location.c_str(), kRuntimeISA);
127   LOG(INFO) << "elf_filename=" << elf_filename;
128 
129   UnreserveImageSpace();
130   uint8_t* dl_oatdata = nullptr;
131   uint8_t* dl_oatexec = nullptr;
132   uint8_t* dl_oatlastword = nullptr;
133 
134   std::unique_ptr<File> file(OS::OpenFileForReading(elf_filename.c_str()));
135   ASSERT_TRUE(file.get() != nullptr) << elf_filename;
136   ASSERT_NO_FATAL_FAILURE(FindSymbolAddress(file.get(), "oatdata", &dl_oatdata));
137   ASSERT_NO_FATAL_FAILURE(FindSymbolAddress(file.get(), "oatexec", &dl_oatexec));
138   ASSERT_NO_FATAL_FAILURE(FindSymbolAddress(file.get(), "oatlastword", &dl_oatlastword));
139   {
140     std::string error_msg;
141     std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(),
142                                               /*low_4gb=*/false,
143                                               &error_msg));
144     CHECK(ef.get() != nullptr) << error_msg;
145     size_t size;
146     bool success = ef->GetLoadedSize(&size, &error_msg);
147     CHECK(success) << error_msg;
148     MemMap reservation = MemMap::MapAnonymous("ElfWriterTest#dlsym reservation",
149                                               RoundUp(size, MemMap::GetPageSize()),
150                                               PROT_NONE,
151                                               /*low_4gb=*/true,
152                                               &error_msg);
153     CHECK(reservation.IsValid()) << error_msg;
154     uint8_t* base = reservation.Begin();
155     success = ef->Load(/*executable=*/false, /*low_4gb=*/false, &reservation, &error_msg);
156     CHECK(success) << error_msg;
157     CHECK(!reservation.IsValid());
158     EXPECT_EQ(reinterpret_cast<uintptr_t>(dl_oatdata) + reinterpret_cast<uintptr_t>(base),
159               reinterpret_cast<uintptr_t>(ef->FindDynamicSymbolAddress("oatdata")));
160     EXPECT_EQ(reinterpret_cast<uintptr_t>(dl_oatexec) + reinterpret_cast<uintptr_t>(base),
161               reinterpret_cast<uintptr_t>(ef->FindDynamicSymbolAddress("oatexec")));
162     EXPECT_EQ(reinterpret_cast<uintptr_t>(dl_oatlastword) + reinterpret_cast<uintptr_t>(base),
163               reinterpret_cast<uintptr_t>(ef->FindDynamicSymbolAddress("oatlastword")));
164   }
165 }
166 
HasSection(File * file,const char * section_name,bool * result)167 static void HasSection(File* file, const char* section_name, /*out*/ bool* result) {
168   ASSERT_NE(elf_version(EV_CURRENT), EV_NONE) << "libelf initialization failed: " << elf_errmsg(-1);
169 
170   Elf* elf = elf_begin(file->Fd(), ELF_C_READ, /*ref=*/nullptr);
171   ASSERT_NE(elf, nullptr) << elf_errmsg(-1);
172   auto elf_cleanup = android::base::make_scope_guard([&]() { elf_end(elf); });
173 
174   size_t shstrndx = 0;
175   ASSERT_EQ(elf_getshdrstrndx(elf, &shstrndx), 0) << elf_errmsg(-1);
176 
177   Elf_Scn* dyn_scn = nullptr;
178   GElf_Shdr scn_hdr;
179   while ((dyn_scn = elf_nextscn(elf, dyn_scn)) != nullptr) {
180     ASSERT_EQ(gelf_getshdr(dyn_scn, &scn_hdr), &scn_hdr) << elf_errmsg(-1);
181     const char* name = elf_strptr(elf, shstrndx, scn_hdr.sh_name);
182     if (strcmp(name, section_name) == 0) {
183       *result = true;
184       return;
185     }
186   }
187   *result = false;
188 }
189 
TEST_F(ElfWriterTest,CheckBuildIdPresent)190 TEST_F(ElfWriterTest, CheckBuildIdPresent) {
191   std::string elf_location = GetCoreOatLocation();
192   std::string elf_filename = GetSystemImageFilename(elf_location.c_str(), kRuntimeISA);
193   LOG(INFO) << "elf_filename=" << elf_filename;
194 
195   std::unique_ptr<File> file(OS::OpenFileForReading(elf_filename.c_str()));
196   ASSERT_TRUE(file.get() != nullptr);
197 
198   bool result;
199   ASSERT_NO_FATAL_FAILURE(HasSection(file.get(), ".note.gnu.build-id", &result));
200   EXPECT_TRUE(result);
201 }
202 
203 // Check that dynamic sections (.dynamic, .dynsym, .dynstr, .hash) in an oat file are formed
204 // correctly so that dynamic symbols can be successfully looked up.
TEST_F(ElfWriterTest,CheckDynamicSection)205 TEST_F(ElfWriterTest, CheckDynamicSection) {
206   // This function generates an oat file with the specified oat data sizes and offsets and
207   // verifies it:
208   // * Checks that the file can be loaded by the ELF loader.
209   // * Checks that the expected dynamic symbols exist and point to the corresponding data
210   //   in the loaded file.
211   // * Checks the alignment of the oat data.
212   // The function returns the number of dynamic symbols (excluding "lastword" ones) in the
213   // generated oat file.
214   auto verify = [this](size_t rodata_size,
215                        size_t text_size,
216                        size_t data_img_rel_ro_size,
217                        size_t data_img_rel_ro_app_image_offset,
218                        size_t bss_size,
219                        size_t bss_methods_offset,
220                        size_t bss_roots_offset,
221                        size_t dex_section_size,
222                        /*out*/ size_t* number_of_dynamic_symbols) {
223     SCOPED_TRACE(::testing::Message()
224                  << "rodata_size: " << rodata_size << ", text_size: " << text_size
225                  << ", data_img_rel_ro_size: " << data_img_rel_ro_size
226                  << ", data_img_rel_ro_app_image_offset: " << data_img_rel_ro_app_image_offset
227                  << ", bss_size: " << bss_size << ", bss_methods_offset: " << bss_methods_offset
228                  << ", bss_roots_offset: " << bss_roots_offset
229                  << ", dex_section_size: " << dex_section_size);
230 
231     *number_of_dynamic_symbols = 1;  // "oatdata".
232     std::vector<uint8_t> rodata(rodata_size, 0xAA);
233     std::vector<uint8_t> text(text_size, 0xBB);
234     std::vector<uint8_t> data_img_rel_ro(data_img_rel_ro_app_image_offset, 0xCC);
235     size_t data_img_rel_ro_app_image_size = data_img_rel_ro_size - data_img_rel_ro_app_image_offset;
236     data_img_rel_ro.insert(data_img_rel_ro.cend(), data_img_rel_ro_app_image_size, 0xDD);
237 
238     ScratchFile tmp_base, tmp_oat(tmp_base, ".oat");
239     WriteElf(tmp_oat.GetFile(),
240              rodata,
241              text,
242              data_img_rel_ro,
243              data_img_rel_ro_app_image_offset,
244              bss_size,
245              bss_methods_offset,
246              bss_roots_offset,
247              dex_section_size);
248 
249     std::string error_msg;
250     std::unique_ptr<ElfFile> ef(ElfFile::Open(tmp_oat.GetFile(),
251                                               /*low_4gb=*/false,
252                                               &error_msg));
253     ASSERT_NE(ef.get(), nullptr) << error_msg;
254     ASSERT_TRUE(ef->Load(/*executable=*/false,
255                          /*low_4gb=*/false,
256                          /*reservation=*/nullptr,
257                          &error_msg))
258         << error_msg;
259 
260     const uint8_t* oatdata_ptr = ef->FindDynamicSymbolAddress("oatdata");
261     ASSERT_NE(oatdata_ptr, nullptr);
262     EXPECT_EQ(memcmp(oatdata_ptr, rodata.data(), rodata.size()), 0);
263 
264     size_t page_size = GetPageSizeSlow();
265     size_t elf_word_size = ef->Is64Bit() ? sizeof(ElfTypes64::Word) : sizeof(ElfTypes32::Word);
266 
267     if (text_size != 0u) {
268       *number_of_dynamic_symbols += 1;
269       const uint8_t* text_ptr = ef->FindDynamicSymbolAddress("oatexec");
270       ASSERT_NE(text_ptr, nullptr);
271       ASSERT_TRUE(IsAlignedParam(text_ptr, page_size));
272       EXPECT_EQ(memcmp(text_ptr, text.data(), text.size()), 0);
273 
274       const uint8_t* oatlastword_ptr = ef->FindDynamicSymbolAddress("oatlastword");
275       ASSERT_NE(oatlastword_ptr, nullptr);
276       EXPECT_EQ(static_cast<size_t>(oatlastword_ptr - text_ptr), text_size - elf_word_size);
277     } else if (rodata_size != 0u) {
278       const uint8_t* oatlastword_ptr = ef->FindDynamicSymbolAddress("oatlastword");
279       ASSERT_NE(oatlastword_ptr, nullptr);
280       EXPECT_EQ(static_cast<size_t>(oatlastword_ptr - oatdata_ptr), rodata_size - elf_word_size);
281     }
282 
283     if (data_img_rel_ro_size != 0u) {
284       *number_of_dynamic_symbols += 1;
285       const uint8_t* oatdataimgrelro_ptr = ef->FindDynamicSymbolAddress("oatdataimgrelro");
286       ASSERT_NE(oatdataimgrelro_ptr, nullptr);
287       ASSERT_TRUE(IsAlignedParam(oatdataimgrelro_ptr, page_size));
288       EXPECT_EQ(memcmp(oatdataimgrelro_ptr, data_img_rel_ro.data(), data_img_rel_ro.size()), 0);
289 
290       const uint8_t* oatdataimgrelrolastword_ptr =
291           ef->FindDynamicSymbolAddress("oatdataimgrelrolastword");
292       ASSERT_NE(oatdataimgrelrolastword_ptr, nullptr);
293       EXPECT_EQ(static_cast<size_t>(oatdataimgrelrolastword_ptr - oatdataimgrelro_ptr),
294           data_img_rel_ro_size - elf_word_size);
295 
296       if (data_img_rel_ro_app_image_offset != data_img_rel_ro_size) {
297         *number_of_dynamic_symbols += 1;
298         const uint8_t* oatdataimgrelroappimage_ptr =
299             ef->FindDynamicSymbolAddress("oatdataimgrelroappimage");
300         ASSERT_NE(oatdataimgrelroappimage_ptr, nullptr);
301         EXPECT_EQ(static_cast<size_t>(oatdataimgrelroappimage_ptr - oatdataimgrelro_ptr),
302           data_img_rel_ro_app_image_offset);
303       }
304 
305       if (bss_size != 0u) {
306         *number_of_dynamic_symbols += 1;
307         const uint8_t* bss_ptr = ef->FindDynamicSymbolAddress("oatbss");
308         ASSERT_NE(bss_ptr, nullptr);
309         ASSERT_TRUE(IsAlignedParam(bss_ptr, page_size));
310 
311         if (bss_methods_offset != bss_roots_offset) {
312           *number_of_dynamic_symbols += 1;
313           const uint8_t* oatbssmethods_ptr = ef->FindDynamicSymbolAddress("oatbssmethods");
314           ASSERT_NE(oatbssmethods_ptr, nullptr);
315           EXPECT_EQ(static_cast<size_t>(oatbssmethods_ptr - bss_ptr), bss_methods_offset);
316         }
317 
318         if (bss_roots_offset != bss_size) {
319           *number_of_dynamic_symbols += 1;
320           const uint8_t* oatbssroots_ptr = ef->FindDynamicSymbolAddress("oatbssroots");
321           ASSERT_NE(oatbssroots_ptr, nullptr);
322           EXPECT_EQ(static_cast<size_t>(oatbssroots_ptr - bss_ptr), bss_roots_offset);
323         }
324 
325         const uint8_t* oatbsslastword_ptr = ef->FindDynamicSymbolAddress("oatbsslastword");
326         ASSERT_NE(oatbsslastword_ptr, nullptr);
327         EXPECT_EQ(static_cast<size_t>(oatbsslastword_ptr - bss_ptr), bss_size - elf_word_size);
328       }
329     }
330 
331     if (dex_section_size != 0u) {
332       *number_of_dynamic_symbols += 1;
333       const uint8_t* dex_ptr = ef->FindDynamicSymbolAddress("oatdex");
334       ASSERT_NE(dex_ptr, nullptr);
335       ASSERT_TRUE(IsAlignedParam(dex_ptr, page_size));
336       const uint8_t* oatdexlastword_ptr = ef->FindDynamicSymbolAddress("oatdexlastword");
337       EXPECT_EQ(static_cast<size_t>(oatdexlastword_ptr - dex_ptr),
338           dex_section_size - elf_word_size);
339     }
340   };
341 
342   // If a symbol requires some other ones (e.g. kBssMethods requires kBss),
343   // it should be listed after them.
344   enum class Symbol {
345     kRodata,
346     kText,
347     kDataImgRelRo,
348     kDataImgRelRoAppImage,
349     kBss,
350     kBssMethods,
351     kBssRoots,
352     kDex,
353     kLast = kDex
354   };
355 
356   constexpr size_t kNumberOfSymbols = static_cast<size_t>(Symbol::kLast) + 1;
357 
358   // Use an unaligned section size to verify that ElfWriter properly aligns sections in this case.
359   // We can use an arbitrary value that is greater than or equal to an ElfWord (4 bytes).
360   constexpr size_t kSectionSize = 127u;
361   // Offset in .data.img.rel.ro section from its beginning. We can use any value in the range
362   // [0, kSectionSize).
363   constexpr size_t kDataImgRelRoAppImageOffset = kSectionSize / 2;
364   // Offsets in .bss from its beginning. We can use any value in the range [0, kSectionSize),
365   // kBssMethodsOffset should be less than or equal to kBssRootsOffset.
366   constexpr size_t kBssMethodsOffset = kSectionSize / 3;
367   constexpr size_t kBssRootsOffset = 2 * kBssMethodsOffset;
368 
369   auto exists = [](Symbol symbol, const std::bitset<kNumberOfSymbols> &symbols) {
370     return symbols.test(static_cast<size_t>(symbol));
371   };
372 
373   auto get_size = [&](Symbol symbol, const std::bitset<kNumberOfSymbols> &symbols) -> size_t {
374     return exists(symbol, symbols) ? kSectionSize : 0;
375   };
376 
377   std::bitset<kNumberOfSymbols> symbols;
378   symbols.set();
379 
380   // Check cases that lead to a different number of dynamic symbols in an oat file.
381   // We start with the case where all symbols exist (corresponding to the bitset 11111111)
382   // and continue to the case where only "oatdata" exists:
383   //  11111111 - all symbols exist.
384   //  01111111 - "oatdex" doesn't exist (least significant bit corresponds to "oatdata").
385   //  00111111 - "oatdex" and "oatbss" don't exist.
386   //  ...
387   //  00000001 - only "oatdata" exists.
388   while (symbols.any()) {
389     DCHECK_IMPLIES(exists(Symbol::kDataImgRelRoAppImage, symbols),
390         exists(Symbol::kDataImgRelRo, symbols));
391     DCHECK_IMPLIES(exists(Symbol::kBssMethods, symbols), exists(Symbol::kBss, symbols));
392     DCHECK_IMPLIES(exists(Symbol::kBssRoots, symbols), exists(Symbol::kBss, symbols));
393     DCHECK_IMPLIES(exists(Symbol::kBssRoots, symbols), exists(Symbol::kBssMethods, symbols));
394 
395     size_t data_img_rel_ro_size = get_size(Symbol::kDataImgRelRo, symbols);
396     size_t bss_size = get_size(Symbol::kBss, symbols);
397     size_t number_of_dynamic_symbols = 0;
398     verify(get_size(Symbol::kRodata, symbols),
399            get_size(Symbol::kText, symbols),
400            data_img_rel_ro_size,
401            exists(Symbol::kDataImgRelRoAppImage, symbols)
402               ? kDataImgRelRoAppImageOffset
403               : data_img_rel_ro_size,
404            bss_size,
405            exists(Symbol::kBssMethods, symbols) ? kBssMethodsOffset : bss_size,
406            exists(Symbol::kBssRoots, symbols) ? kBssRootsOffset : bss_size,
407            get_size(Symbol::kDex, symbols),
408            &number_of_dynamic_symbols);
409     EXPECT_EQ(number_of_dynamic_symbols, symbols.count())
410       << "number_of_dynamic_symbols: " << number_of_dynamic_symbols
411       << ", symbols: " << symbols;
412     symbols >>= 1;
413   }
414 }
415 
416 }  // namespace linker
417 }  // namespace art
418