blob: e32e4573538b91dc1ba3f6c21b95b20788c445c0 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// A crazy linker test to:
// - Load a library (libfoo.so) with the linker.
// - Find the address of the "Foo" function in it.
// - Call the function.
// - Close the library.
#include <crazy_linker.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
static void Panic(const char* fmt, ...) {
va_list args;
fprintf(stderr, "PANIC: ");
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
exit(1);
}
static double now_ms() {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * 1000.) + (ts.tv_nsec / 1000000.);
}
static void drop_caches() {
int fd = open("/proc/sys/vm/drop_caches", O_RDWR);
if (fd < 0) {
fprintf(stderr,
"Could not drop caches! Please run this program as root!\n");
return;
}
write(fd, "3\n", 2);
close(fd);
}
class ScopedTimer {
public:
ScopedTimer(const char* name) {
name_ = name;
start_ms_ = now_ms();
}
~ScopedTimer() {
double elapsed_ms = now_ms() - start_ms_;
printf("Timer %s: %.1f\n", name_, elapsed_ms);
}
private:
const char* name_;
double start_ms_;
};
int main(int argc, char** argv) {
const char* library_path = "libcrazy_linker_tests_libfoo.so";
if (argc >= 2)
library_path = argv[1];
{ ScopedTimer null_timer("empty"); }
// Load the library with dlopen().
void* lib;
drop_caches();
{
ScopedTimer timer("dlopen");
lib = dlopen(library_path, RTLD_NOW);
}
if (!lib)
Panic("Could not load library with dlopen(): %s\n", dlerror());
dlclose(lib);
crazy_library_t* library;
crazy_context_t* context = crazy_context_create();
// Ensure the program looks in its own directory too.
crazy_add_search_path_for_address(reinterpret_cast<void*>(&main));
// Load the library with the crazy linker.
drop_caches();
{
ScopedTimer timer("crazy_linker");
// Load libfoo.so
if (!crazy_library_open(&library, library_path, context)) {
Panic("Could not open library: %s\n", crazy_context_get_error(context));
}
}
crazy_library_close(library);
// Load the library with the crazy linker. Preload libOpenSLES.so
drop_caches();
void* sles_lib = dlopen("libOpenSLES.so", RTLD_NOW);
{
ScopedTimer timer("crazy_linker (preload libOpenSLES.so)");
// Load libfoo.so
if (!crazy_library_open(&library, library_path, context)) {
Panic("Could not open library: %s\n", crazy_context_get_error(context));
}
}
crazy_library_close(library);
dlclose(sles_lib);
// Load the library with the crazy linker. Preload libOpenSLES.so
{
drop_caches();
void* sys1_lib = dlopen("libandroid.so", RTLD_NOW);
void* sys2_lib = dlopen("libjnigraphics.so", RTLD_NOW);
void* sys3_lib = dlopen("libOpenSLES.so", RTLD_NOW);
{
ScopedTimer timer("crazy_linker (preload 3 system libs)");
// Load libfoo.so
if (!crazy_library_open(&library, library_path, context)) {
Panic("Could not open library: %s\n", crazy_context_get_error(context));
}
}
crazy_library_close(library);
dlclose(sys3_lib);
dlclose(sys2_lib);
dlclose(sys1_lib);
}
// Load the library with the crazy linker. Create a shared RELRO as well.
drop_caches();
{
ScopedTimer timer("crazy_linker (with RELRO)");
// Load libfoo.so
if (!crazy_library_open(&library, library_path, context)) {
Panic("Could not open library: %s\n", crazy_context_get_error(context));
}
size_t relro_start = 0;
size_t relro_size = 0;
int relro_fd = -1;
if (!crazy_library_create_shared_relro(library, context,
0 /* load_address */, &relro_start,
&relro_size, &relro_fd)) {
Panic("Could not create shared RELRO: %s\n",
crazy_context_get_error(context));
}
close(relro_fd);
}
crazy_library_close(library);
printf("OK\n");
return 0;
}