1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// A crazy linker test to:
6// - Load a library (libfoo.so) with the linker.
7// - Find the address of the "Foo" function in it.
8// - Call the function.
9// - Close the library.
10
11#include <crazy_linker.h>
12
13#include <stdarg.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <time.h>
17#include <unistd.h>
18#include <fcntl.h>
19
20static void Panic(const char* fmt, ...) {
21  va_list args;
22  fprintf(stderr, "PANIC: ");
23  va_start(args, fmt);
24  vfprintf(stderr, fmt, args);
25  va_end(args);
26  exit(1);
27}
28
29static double now_ms() {
30  struct timespec ts;
31  clock_gettime(CLOCK_MONOTONIC, &ts);
32  return (ts.tv_sec * 1000.) + (ts.tv_nsec / 1000000.);
33}
34
35static void drop_caches() {
36  int fd = open("/proc/sys/vm/drop_caches", O_RDWR);
37  if (fd < 0) {
38    fprintf(stderr,
39            "Could not drop caches! Please run this program as root!\n");
40    return;
41  }
42  write(fd, "3\n", 2);
43  close(fd);
44}
45
46class ScopedTimer {
47 public:
48  ScopedTimer(const char* name) {
49    name_ = name;
50    start_ms_ = now_ms();
51  }
52
53  ~ScopedTimer() {
54    double elapsed_ms = now_ms() - start_ms_;
55    printf("Timer %s: %.1f\n", name_, elapsed_ms);
56  }
57
58 private:
59  const char* name_;
60  double start_ms_;
61};
62
63int main(int argc, char** argv) {
64  const char* library_path = "libfoo.so";
65  if (argc >= 2)
66    library_path = argv[1];
67
68  { ScopedTimer null_timer("empty"); }
69
70  // Load the library with dlopen().
71  void* lib;
72  drop_caches();
73  {
74    ScopedTimer timer("dlopen");
75    lib = dlopen(library_path, RTLD_NOW);
76  }
77  if (!lib)
78    Panic("Could not load library with dlopen(): %s\n", dlerror());
79
80  dlclose(lib);
81
82  crazy_library_t* library;
83  crazy_context_t* context = crazy_context_create();
84
85  // Ensure the program looks in its own directory too.
86  crazy_context_add_search_path_for_address(context,
87                                            reinterpret_cast<void*>(&main));
88
89  // Load the library with the crazy linker.
90  drop_caches();
91  {
92    ScopedTimer timer("crazy_linker");
93    // Load libfoo.so
94    if (!crazy_library_open(&library, library_path, context)) {
95      Panic("Could not open library: %s\n", crazy_context_get_error(context));
96    }
97  }
98  crazy_library_close(library);
99
100  // Load the library with the crazy linker. Preload libOpenSLES.so
101  drop_caches();
102  void* sles_lib = dlopen("libOpenSLES.so", RTLD_NOW);
103  {
104    ScopedTimer timer("crazy_linker (preload libOpenSLES.so)");
105    // Load libfoo.so
106    if (!crazy_library_open(&library, library_path, context)) {
107      Panic("Could not open library: %s\n", crazy_context_get_error(context));
108    }
109  }
110  crazy_library_close(library);
111  dlclose(sles_lib);
112
113  // Load the library with the crazy linker. Preload libOpenSLES.so
114  {
115    drop_caches();
116    void* sys1_lib = dlopen("libandroid.so", RTLD_NOW);
117    void* sys2_lib = dlopen("libjnigraphics.so", RTLD_NOW);
118    void* sys3_lib = dlopen("libOpenSLES.so", RTLD_NOW);
119    {
120      ScopedTimer timer("crazy_linker (preload 3 system libs)");
121      // Load libfoo.so
122      if (!crazy_library_open(&library, library_path, context)) {
123        Panic("Could not open library: %s\n", crazy_context_get_error(context));
124      }
125    }
126    crazy_library_close(library);
127    dlclose(sys3_lib);
128    dlclose(sys2_lib);
129    dlclose(sys1_lib);
130  }
131
132  // Load the library with the crazy linker. Create a shared RELRO as well.
133  drop_caches();
134  {
135    ScopedTimer timer("crazy_linker (with RELRO)");
136    // Load libfoo.so
137    if (!crazy_library_open(&library, library_path, context)) {
138      Panic("Could not open library: %s\n", crazy_context_get_error(context));
139    }
140
141    if (!crazy_library_enable_relro_sharing(library, context)) {
142      Panic("Could not create shared RELRO: %s\n",
143            crazy_context_get_error(context));
144    }
145  }
146  crazy_library_close(library);
147
148  printf("OK\n");
149  return 0;
150}