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