1*6777b538SAndroid Build Coastguard Worker // Copyright 2020 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include <link.h>
6*6777b538SAndroid Build Coastguard Worker #include <sys/mman.h>
7*6777b538SAndroid Build Coastguard Worker #include <sys/prctl.h>
8*6777b538SAndroid Build Coastguard Worker #include <sys/utsname.h>
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker #include "base/android/linker/linker_jni.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/files/scoped_file.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/system/sys_info.h"
14*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
15*6777b538SAndroid Build Coastguard Worker
16*6777b538SAndroid Build Coastguard Worker extern char __executable_start;
17*6777b538SAndroid Build Coastguard Worker
18*6777b538SAndroid Build Coastguard Worker extern "C" {
19*6777b538SAndroid Build Coastguard Worker
20*6777b538SAndroid Build Coastguard Worker // This function is exported by the dynamic linker but never declared in any
21*6777b538SAndroid Build Coastguard Worker // official header for some architecture/version combinations.
22*6777b538SAndroid Build Coastguard Worker int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data),
23*6777b538SAndroid Build Coastguard Worker void* data) __attribute__((weak_import));
24*6777b538SAndroid Build Coastguard Worker
25*6777b538SAndroid Build Coastguard Worker } // extern "C"
26*6777b538SAndroid Build Coastguard Worker
27*6777b538SAndroid Build Coastguard Worker namespace chromium_android_linker {
28*6777b538SAndroid Build Coastguard Worker
29*6777b538SAndroid Build Coastguard Worker namespace {
30*6777b538SAndroid Build Coastguard Worker
31*6777b538SAndroid Build Coastguard Worker // Implements the old method of finding library and RELRO ranges by providing a
32*6777b538SAndroid Build Coastguard Worker // callback for use with dl_iterate_phdr(3). Data from the field has shown that
33*6777b538SAndroid Build Coastguard Worker // this method makes library loading significantly slower than
34*6777b538SAndroid Build Coastguard Worker // android_dlopen_ext(), it was replaced by the exuivalent one:
35*6777b538SAndroid Build Coastguard Worker // NativeLibInfo::FindRelroAndLibraryRangesInElf().
36*6777b538SAndroid Build Coastguard Worker class LibraryRangeFinder {
37*6777b538SAndroid Build Coastguard Worker public:
LibraryRangeFinder(uintptr_t address)38*6777b538SAndroid Build Coastguard Worker explicit LibraryRangeFinder(uintptr_t address) : load_address_(address) {}
39*6777b538SAndroid Build Coastguard Worker
load_address() const40*6777b538SAndroid Build Coastguard Worker uintptr_t load_address() const { return load_address_; }
load_size() const41*6777b538SAndroid Build Coastguard Worker size_t load_size() const { return load_size_; }
relro_start() const42*6777b538SAndroid Build Coastguard Worker uintptr_t relro_start() const { return relro_start_; }
relro_size() const43*6777b538SAndroid Build Coastguard Worker size_t relro_size() const { return relro_size_; }
44*6777b538SAndroid Build Coastguard Worker
45*6777b538SAndroid Build Coastguard Worker static int VisitLibraryPhdrs(dl_phdr_info* info,
46*6777b538SAndroid Build Coastguard Worker [[maybe_unused]] size_t size,
47*6777b538SAndroid Build Coastguard Worker void* data);
48*6777b538SAndroid Build Coastguard Worker
49*6777b538SAndroid Build Coastguard Worker private:
50*6777b538SAndroid Build Coastguard Worker uintptr_t load_address_;
51*6777b538SAndroid Build Coastguard Worker size_t load_size_ = 0;
52*6777b538SAndroid Build Coastguard Worker uintptr_t relro_start_ = 0;
53*6777b538SAndroid Build Coastguard Worker size_t relro_size_ = 0;
54*6777b538SAndroid Build Coastguard Worker };
55*6777b538SAndroid Build Coastguard Worker
56*6777b538SAndroid Build Coastguard Worker // Callback for dl_iterate_phdr(). From program headers (phdr(s)) of a loaded
57*6777b538SAndroid Build Coastguard Worker // library determines its load address, and in case it is equal to
58*6777b538SAndroid Build Coastguard Worker // |load_address()|, extracts the RELRO and size information from
59*6777b538SAndroid Build Coastguard Worker // corresponding phdr(s).
60*6777b538SAndroid Build Coastguard Worker // static
VisitLibraryPhdrs(dl_phdr_info * info,size_t size,void * data)61*6777b538SAndroid Build Coastguard Worker int LibraryRangeFinder::VisitLibraryPhdrs(dl_phdr_info* info,
62*6777b538SAndroid Build Coastguard Worker [[maybe_unused]] size_t size,
63*6777b538SAndroid Build Coastguard Worker void* data) {
64*6777b538SAndroid Build Coastguard Worker auto* finder = reinterpret_cast<LibraryRangeFinder*>(data);
65*6777b538SAndroid Build Coastguard Worker ElfW(Addr) lookup_address = static_cast<ElfW(Addr)>(finder->load_address());
66*6777b538SAndroid Build Coastguard Worker
67*6777b538SAndroid Build Coastguard Worker // Use max and min vaddr to compute the library's load size.
68*6777b538SAndroid Build Coastguard Worker auto min_vaddr = std::numeric_limits<ElfW(Addr)>::max();
69*6777b538SAndroid Build Coastguard Worker ElfW(Addr) max_vaddr = 0;
70*6777b538SAndroid Build Coastguard Worker ElfW(Addr) min_relro_vaddr = ~0;
71*6777b538SAndroid Build Coastguard Worker ElfW(Addr) max_relro_vaddr = 0;
72*6777b538SAndroid Build Coastguard Worker
73*6777b538SAndroid Build Coastguard Worker const size_t kPageSize = sysconf(_SC_PAGESIZE);
74*6777b538SAndroid Build Coastguard Worker bool is_matching = false;
75*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < info->dlpi_phnum; ++i) {
76*6777b538SAndroid Build Coastguard Worker const ElfW(Phdr)* phdr = &info->dlpi_phdr[i];
77*6777b538SAndroid Build Coastguard Worker switch (phdr->p_type) {
78*6777b538SAndroid Build Coastguard Worker case PT_LOAD:
79*6777b538SAndroid Build Coastguard Worker // See if this segment's load address matches the value passed to
80*6777b538SAndroid Build Coastguard Worker // android_dlopen_ext as |extinfo.reserved_addr|.
81*6777b538SAndroid Build Coastguard Worker //
82*6777b538SAndroid Build Coastguard Worker // Here and below, the virtual address in memory is computed by
83*6777b538SAndroid Build Coastguard Worker // address == info->dlpi_addr + program_header->p_vaddr
84*6777b538SAndroid Build Coastguard Worker // that is, the p_vaddr fields is relative to the object base address.
85*6777b538SAndroid Build Coastguard Worker // See dl_iterate_phdr(3) for details.
86*6777b538SAndroid Build Coastguard Worker if (lookup_address == info->dlpi_addr + phdr->p_vaddr)
87*6777b538SAndroid Build Coastguard Worker is_matching = true;
88*6777b538SAndroid Build Coastguard Worker
89*6777b538SAndroid Build Coastguard Worker if (phdr->p_vaddr < min_vaddr)
90*6777b538SAndroid Build Coastguard Worker min_vaddr = phdr->p_vaddr;
91*6777b538SAndroid Build Coastguard Worker if (phdr->p_vaddr + phdr->p_memsz > max_vaddr)
92*6777b538SAndroid Build Coastguard Worker max_vaddr = phdr->p_vaddr + phdr->p_memsz;
93*6777b538SAndroid Build Coastguard Worker break;
94*6777b538SAndroid Build Coastguard Worker case PT_GNU_RELRO:
95*6777b538SAndroid Build Coastguard Worker min_relro_vaddr = PageStart(kPageSize, phdr->p_vaddr);
96*6777b538SAndroid Build Coastguard Worker max_relro_vaddr = phdr->p_vaddr + phdr->p_memsz;
97*6777b538SAndroid Build Coastguard Worker
98*6777b538SAndroid Build Coastguard Worker // As of 2020-11 in libmonochrome.so RELRO is covered by a LOAD segment.
99*6777b538SAndroid Build Coastguard Worker // It is not clear whether this property is going to be guaranteed in
100*6777b538SAndroid Build Coastguard Worker // the future. Include the RELRO segment as part of the 'load size'.
101*6777b538SAndroid Build Coastguard Worker // This way a potential future change in layout of LOAD segments would
102*6777b538SAndroid Build Coastguard Worker // not open address space for racy mmap(MAP_FIXED).
103*6777b538SAndroid Build Coastguard Worker if (min_relro_vaddr < min_vaddr)
104*6777b538SAndroid Build Coastguard Worker min_vaddr = min_relro_vaddr;
105*6777b538SAndroid Build Coastguard Worker if (max_vaddr < max_relro_vaddr)
106*6777b538SAndroid Build Coastguard Worker max_vaddr = max_relro_vaddr;
107*6777b538SAndroid Build Coastguard Worker break;
108*6777b538SAndroid Build Coastguard Worker default:
109*6777b538SAndroid Build Coastguard Worker break;
110*6777b538SAndroid Build Coastguard Worker }
111*6777b538SAndroid Build Coastguard Worker }
112*6777b538SAndroid Build Coastguard Worker
113*6777b538SAndroid Build Coastguard Worker // Fill out size and relro information if there was a match.
114*6777b538SAndroid Build Coastguard Worker if (is_matching) {
115*6777b538SAndroid Build Coastguard Worker finder->load_size_ =
116*6777b538SAndroid Build Coastguard Worker PageEnd(kPageSize, max_vaddr) - PageStart(kPageSize, min_vaddr);
117*6777b538SAndroid Build Coastguard Worker finder->relro_size_ = PageEnd(kPageSize, max_relro_vaddr) -
118*6777b538SAndroid Build Coastguard Worker PageStart(kPageSize, min_relro_vaddr);
119*6777b538SAndroid Build Coastguard Worker finder->relro_start_ =
120*6777b538SAndroid Build Coastguard Worker info->dlpi_addr + PageStart(kPageSize, min_relro_vaddr);
121*6777b538SAndroid Build Coastguard Worker
122*6777b538SAndroid Build Coastguard Worker return 1;
123*6777b538SAndroid Build Coastguard Worker }
124*6777b538SAndroid Build Coastguard Worker
125*6777b538SAndroid Build Coastguard Worker return 0;
126*6777b538SAndroid Build Coastguard Worker }
127*6777b538SAndroid Build Coastguard Worker
128*6777b538SAndroid Build Coastguard Worker } // namespace
129*6777b538SAndroid Build Coastguard Worker
130*6777b538SAndroid Build Coastguard Worker // These tests get linked with base_unittests and leave JNI uninitialized. The
131*6777b538SAndroid Build Coastguard Worker // tests must not execute any parts relying on initialization with JNI_Onload().
132*6777b538SAndroid Build Coastguard Worker
133*6777b538SAndroid Build Coastguard Worker class LinkerTest : public testing::Test {
134*6777b538SAndroid Build Coastguard Worker public:
135*6777b538SAndroid Build Coastguard Worker LinkerTest() = default;
136*6777b538SAndroid Build Coastguard Worker ~LinkerTest() override = default;
137*6777b538SAndroid Build Coastguard Worker };
138*6777b538SAndroid Build Coastguard Worker
139*6777b538SAndroid Build Coastguard Worker // Checks that NativeLibInfo::CreateSharedRelroFd() creates a shared memory
140*6777b538SAndroid Build Coastguard Worker // region that is 'sealed' as read-only.
TEST_F(LinkerTest,CreatedRegionIsSealed)141*6777b538SAndroid Build Coastguard Worker TEST_F(LinkerTest, CreatedRegionIsSealed) {
142*6777b538SAndroid Build Coastguard Worker if (!NativeLibInfo::SharedMemoryFunctionsSupportedForTesting()) {
143*6777b538SAndroid Build Coastguard Worker // The Linker uses functions from libandroid.so that are not available
144*6777b538SAndroid Build Coastguard Worker // on Android releases before O. Disable unittests for old releases.
145*6777b538SAndroid Build Coastguard Worker return;
146*6777b538SAndroid Build Coastguard Worker }
147*6777b538SAndroid Build Coastguard Worker
148*6777b538SAndroid Build Coastguard Worker // Fill a synthetic RELRO region with 0xEE in private anonynous memory.
149*6777b538SAndroid Build Coastguard Worker constexpr size_t kRelroSize = 1 << 21; // 2 MiB.
150*6777b538SAndroid Build Coastguard Worker void* relro_address = mmap(nullptr, kRelroSize, PROT_READ | PROT_WRITE,
151*6777b538SAndroid Build Coastguard Worker MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
152*6777b538SAndroid Build Coastguard Worker ASSERT_NE(MAP_FAILED, relro_address);
153*6777b538SAndroid Build Coastguard Worker NativeLibInfo lib_info = {0, 0};
154*6777b538SAndroid Build Coastguard Worker lib_info.set_relro_info_for_testing(
155*6777b538SAndroid Build Coastguard Worker reinterpret_cast<uintptr_t>(relro_address), kRelroSize);
156*6777b538SAndroid Build Coastguard Worker memset(relro_address, 0xEE, kRelroSize);
157*6777b538SAndroid Build Coastguard Worker
158*6777b538SAndroid Build Coastguard Worker // Create shared RELRO.
159*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(true, lib_info.CreateSharedRelroFdForTesting());
160*6777b538SAndroid Build Coastguard Worker int relro_fd = lib_info.get_relro_fd_for_testing();
161*6777b538SAndroid Build Coastguard Worker ASSERT_NE(-1, relro_fd);
162*6777b538SAndroid Build Coastguard Worker base::ScopedFD scoped_fd(relro_fd);
163*6777b538SAndroid Build Coastguard Worker
164*6777b538SAndroid Build Coastguard Worker // Check that a read-only mapping contains the data originally filled in.
165*6777b538SAndroid Build Coastguard Worker void* ro_address =
166*6777b538SAndroid Build Coastguard Worker mmap(nullptr, kRelroSize, PROT_READ, MAP_SHARED, relro_fd, 0);
167*6777b538SAndroid Build Coastguard Worker ASSERT_NE(MAP_FAILED, ro_address);
168*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(0xEEEEEEEEU, *reinterpret_cast<uint32_t*>(ro_address));
169*6777b538SAndroid Build Coastguard Worker int not_equal = memcmp(relro_address, ro_address, kRelroSize);
170*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(0, not_equal);
171*6777b538SAndroid Build Coastguard Worker munmap(ro_address, kRelroSize);
172*6777b538SAndroid Build Coastguard Worker
173*6777b538SAndroid Build Coastguard Worker // Check that attempts to mmap with PROT_WRITE fail.
174*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(MAP_FAILED, mmap(nullptr, kRelroSize, PROT_READ | PROT_WRITE,
175*6777b538SAndroid Build Coastguard Worker MAP_SHARED, relro_fd, 0));
176*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(MAP_FAILED, mmap(nullptr, kRelroSize, PROT_READ | PROT_WRITE,
177*6777b538SAndroid Build Coastguard Worker MAP_PRIVATE, relro_fd, 0));
178*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(MAP_FAILED,
179*6777b538SAndroid Build Coastguard Worker mmap(nullptr, kRelroSize, PROT_WRITE, MAP_SHARED, relro_fd, 0));
180*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(MAP_FAILED,
181*6777b538SAndroid Build Coastguard Worker mmap(nullptr, kRelroSize, PROT_WRITE, MAP_PRIVATE, relro_fd, 0));
182*6777b538SAndroid Build Coastguard Worker }
183*6777b538SAndroid Build Coastguard Worker
TEST_F(LinkerTest,FindReservedMemoryRegion)184*6777b538SAndroid Build Coastguard Worker TEST_F(LinkerTest, FindReservedMemoryRegion) {
185*6777b538SAndroid Build Coastguard Worker size_t address, size;
186*6777b538SAndroid Build Coastguard Worker
187*6777b538SAndroid Build Coastguard Worker // Find the existing reservation in the current process. The unittest runner
188*6777b538SAndroid Build Coastguard Worker // is forked from the system zygote. The reservation should be found when
189*6777b538SAndroid Build Coastguard Worker // running on recent Android releases, where it is made by the
190*6777b538SAndroid Build Coastguard Worker // reserveAddressSpaceInZygote().
191*6777b538SAndroid Build Coastguard Worker bool found_reservation = FindWebViewReservation(&address, &size);
192*6777b538SAndroid Build Coastguard Worker
193*6777b538SAndroid Build Coastguard Worker if (found_reservation) {
194*6777b538SAndroid Build Coastguard Worker // Check that the size is at least the minimum reserved by Android, as of
195*6777b538SAndroid Build Coastguard Worker // 2021-04.
196*6777b538SAndroid Build Coastguard Worker EXPECT_LE(130U * 1024 * 1024, size);
197*6777b538SAndroid Build Coastguard Worker return;
198*6777b538SAndroid Build Coastguard Worker }
199*6777b538SAndroid Build Coastguard Worker
200*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1223747): Check that only non-low-end Android Q+ devices
201*6777b538SAndroid Build Coastguard Worker // reach this point.
202*6777b538SAndroid Build Coastguard Worker
203*6777b538SAndroid Build Coastguard Worker // Create a properly named synthetic region with a size smaller than a real
204*6777b538SAndroid Build Coastguard Worker // library would need, but still aligned well.
205*6777b538SAndroid Build Coastguard Worker static const size_t kSize = 19U * 1024 * 1024;
206*6777b538SAndroid Build Coastguard Worker void* synthetic_region_start =
207*6777b538SAndroid Build Coastguard Worker mmap(nullptr, kSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
208*6777b538SAndroid Build Coastguard Worker ASSERT_NE(MAP_FAILED, synthetic_region_start);
209*6777b538SAndroid Build Coastguard Worker prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, synthetic_region_start, kSize,
210*6777b538SAndroid Build Coastguard Worker "[anon:libwebview reservation]");
211*6777b538SAndroid Build Coastguard Worker
212*6777b538SAndroid Build Coastguard Worker // Now the region must be found.
213*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(FindWebViewReservation(&address, &size));
214*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(kSize, size);
215*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(reinterpret_cast<void*>(address), synthetic_region_start);
216*6777b538SAndroid Build Coastguard Worker munmap(synthetic_region_start, kSize);
217*6777b538SAndroid Build Coastguard Worker }
218*6777b538SAndroid Build Coastguard Worker
TEST_F(LinkerTest,FindLibraryRanges)219*6777b538SAndroid Build Coastguard Worker TEST_F(LinkerTest, FindLibraryRanges) {
220*6777b538SAndroid Build Coastguard Worker static int var_inside = 3;
221*6777b538SAndroid Build Coastguard Worker
222*6777b538SAndroid Build Coastguard Worker NativeLibInfo lib_info = {0, 0};
223*6777b538SAndroid Build Coastguard Worker uintptr_t executable_start = reinterpret_cast<uintptr_t>(&__executable_start);
224*6777b538SAndroid Build Coastguard Worker lib_info.set_load_address(executable_start);
225*6777b538SAndroid Build Coastguard Worker
226*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(lib_info.FindRelroAndLibraryRangesInElfForTesting());
227*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(executable_start, lib_info.load_address());
228*6777b538SAndroid Build Coastguard Worker
229*6777b538SAndroid Build Coastguard Worker uintptr_t inside_library = reinterpret_cast<uintptr_t>(&var_inside);
230*6777b538SAndroid Build Coastguard Worker EXPECT_LE(executable_start, inside_library);
231*6777b538SAndroid Build Coastguard Worker EXPECT_LE(inside_library,
232*6777b538SAndroid Build Coastguard Worker lib_info.load_address() + lib_info.get_load_size_for_testing());
233*6777b538SAndroid Build Coastguard Worker
234*6777b538SAndroid Build Coastguard Worker EXPECT_LE(lib_info.load_address(), lib_info.get_relro_start_for_testing());
235*6777b538SAndroid Build Coastguard Worker EXPECT_LE(lib_info.get_relro_start_for_testing(),
236*6777b538SAndroid Build Coastguard Worker lib_info.load_address() + lib_info.get_load_size_for_testing());
237*6777b538SAndroid Build Coastguard Worker }
238*6777b538SAndroid Build Coastguard Worker
TEST_F(LinkerTest,FindLibraryRangesWhenLoadAddressWasReset)239*6777b538SAndroid Build Coastguard Worker TEST_F(LinkerTest, FindLibraryRangesWhenLoadAddressWasReset) {
240*6777b538SAndroid Build Coastguard Worker NativeLibInfo other_lib_info = {0, 0};
241*6777b538SAndroid Build Coastguard Worker uintptr_t executable_start = reinterpret_cast<uintptr_t>(&__executable_start);
242*6777b538SAndroid Build Coastguard Worker other_lib_info.set_load_address(executable_start);
243*6777b538SAndroid Build Coastguard Worker other_lib_info.set_relro_fd_for_testing(123);
244*6777b538SAndroid Build Coastguard Worker NativeLibInfo lib_info = {0, 0};
245*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(lib_info.CompareRelroAndReplaceItBy(other_lib_info));
246*6777b538SAndroid Build Coastguard Worker }
247*6777b538SAndroid Build Coastguard Worker
248*6777b538SAndroid Build Coastguard Worker // Check that discovering RELRO segment address ranges and the DSO ranges agrees
249*6777b538SAndroid Build Coastguard Worker // with the method based on dl_iterate_phdr(3). The check is performed on the
250*6777b538SAndroid Build Coastguard Worker // test library, not on libmonochrome.
TEST_F(LinkerTest,LibraryRangesViaIteratePhdr)251*6777b538SAndroid Build Coastguard Worker TEST_F(LinkerTest, LibraryRangesViaIteratePhdr) {
252*6777b538SAndroid Build Coastguard Worker // Find the ranges using dl_iterate_phdr().
253*6777b538SAndroid Build Coastguard Worker if (!dl_iterate_phdr) {
254*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(false) << "dl_iterate_phdr() not found";
255*6777b538SAndroid Build Coastguard Worker }
256*6777b538SAndroid Build Coastguard Worker uintptr_t executable_start = reinterpret_cast<uintptr_t>(&__executable_start);
257*6777b538SAndroid Build Coastguard Worker LibraryRangeFinder finder(executable_start);
258*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(1, dl_iterate_phdr(&LibraryRangeFinder::VisitLibraryPhdrs,
259*6777b538SAndroid Build Coastguard Worker reinterpret_cast<void*>(&finder)));
260*6777b538SAndroid Build Coastguard Worker ASSERT_LE(finder.relro_start() + finder.relro_size(),
261*6777b538SAndroid Build Coastguard Worker finder.load_address() + finder.load_size());
262*6777b538SAndroid Build Coastguard Worker
263*6777b538SAndroid Build Coastguard Worker // Find the ranges by parsing ELF.
264*6777b538SAndroid Build Coastguard Worker NativeLibInfo lib_info2 = {0, 0};
265*6777b538SAndroid Build Coastguard Worker lib_info2.set_load_address(executable_start);
266*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(lib_info2.FindRelroAndLibraryRangesInElfForTesting());
267*6777b538SAndroid Build Coastguard Worker
268*6777b538SAndroid Build Coastguard Worker // Compare results.
269*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(finder.load_address(), lib_info2.load_address());
270*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(finder.load_size(), lib_info2.get_load_size_for_testing());
271*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(finder.relro_start(), lib_info2.get_relro_start_for_testing());
272*6777b538SAndroid Build Coastguard Worker }
273*6777b538SAndroid Build Coastguard Worker
274*6777b538SAndroid Build Coastguard Worker } // namespace chromium_android_linker
275