linker.cpp revision fedbcde6ef552e84bf7ce7598bca7dddf1722d6a
11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
2943043583a8f3a8de34970b550a3e8e8a6fb0fb8Doug Kwan * Copyright (C) 2008, 2009 The Android Open Source Project
31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * All rights reserved.
41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Redistribution and use in source and binary forms, with or without
61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * modification, are permitted provided that the following conditions
71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * are met:
81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *  * Redistributions of source code must retain the above copyright
91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *  * Redistributions in binary form must reproduce the above copyright
111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer in
121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    the documentation and/or other materials provided with the
131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    distribution.
141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * SUCH DAMAGE.
271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <linux/auxvec.h>
301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdio.h>
321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdlib.h>
331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <string.h>
341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <unistd.h>
351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <fcntl.h>
361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <errno.h>
371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <dlfcn.h>
381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/stat.h>
391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
405e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev#include <pthread.h>
411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/mman.h>
431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/atomics.h>
451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* special private C library header - see Android.mk */
471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <bionic_tls.h>
481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker.h"
501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "linker_debug.h"
515c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner#include "linker_format.h"
521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "ba.h"
541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
554a9afcb10151b083cd2d75253385615f459172edIliyan Malchev#define ALLOW_SYMBOLS_FROM_MAIN 1
56ba52b3092f361580a5dea7ab8fbe2a227b55ee43James Dong#define SO_MAX 96
571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
58bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley/* Assume average path length of 64 and max 8 paths */
59bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley#define LDPATH_BUFSIZE 512
60bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley#define LDPATH_MAX 8
61bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
624fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer#define LDPRELOAD_BUFSIZE 512
634fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer#define LDPRELOAD_MAX 8
644fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<<
661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Do NOT use malloc() and friends or pthread_*() code here.
681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Don't use printf() either; it's caused mysterious memory
691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * corruption in the past.
701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * The linker runs before we bring up libc and it's easiest
711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * to make sure it does not depend on any complex libc features
721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * open issues / todo:
741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - are we doing everything we should for ARM_COPY relocations?
761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - cleaner error reporting
771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - after linking, set as much stuff as possible to READONLY
781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   and NOEXEC
791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - linker hardcodes PAGE_SIZE and PAGE_MASK because the kernel
801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   headers provide versions that are negative...
811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - allocate space for soinfo structs dynamically instead of
821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   having a hard limit (64)
831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project*/
841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int link_image(soinfo *si, unsigned wr_offset);
871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int socount = 0;
891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo sopool[SO_MAX];
901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *freelist = NULL;
911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *solist = &libdl_info;
921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *sonext = &libdl_info;
934a9afcb10151b083cd2d75253385615f459172edIliyan Malchev#if ALLOW_SYMBOLS_FROM_MAIN
944a9afcb10151b083cd2d75253385615f459172edIliyan Malchevstatic soinfo *somain; /* main process, always the one after libdl_info */
954a9afcb10151b083cd2d75253385615f459172edIliyan Malchev#endif
961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
97af7315acf6a3a5ac329b04cb543b5d8a95dc26f1Iliyan Malchev
98e100f52f4ad1b70762bbcc5ad9828bd258917ee5Iliyan Malchev/* Set up for the buddy allocator managing the non-prelinked libraries. */
99e100f52f4ad1b70762bbcc5ad9828bd258917ee5Iliyan Malchevstatic struct ba_bits ba_nonprelink_bitmap[(LIBLAST - LIBBASE) / LIBINC];
100e100f52f4ad1b70762bbcc5ad9828bd258917ee5Iliyan Malchevstatic struct ba ba_nonprelink = {
101af7315acf6a3a5ac329b04cb543b5d8a95dc26f1Iliyan Malchev    .base = LIBBASE,
102af7315acf6a3a5ac329b04cb543b5d8a95dc26f1Iliyan Malchev    .size = LIBLAST - LIBBASE,
103af7315acf6a3a5ac329b04cb543b5d8a95dc26f1Iliyan Malchev    .min_alloc = LIBINC,
104bb9eedeff4ddc4550991eb4511003bda8672d6c4Iliyan Malchev    /* max_order will be determined automatically */
105e100f52f4ad1b70762bbcc5ad9828bd258917ee5Iliyan Malchev    .bitmap = ba_nonprelink_bitmap,
106e100f52f4ad1b70762bbcc5ad9828bd258917ee5Iliyan Malchev    .num_entries = sizeof(ba_nonprelink_bitmap)/sizeof(ba_nonprelink_bitmap[0]),
107af7315acf6a3a5ac329b04cb543b5d8a95dc26f1Iliyan Malchev};
108af7315acf6a3a5ac329b04cb543b5d8a95dc26f1Iliyan Malchev
1096ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchevstatic inline int validate_soinfo(soinfo *si)
1106ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev{
1116ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    return (si >= sopool && si < sopool + SO_MAX) ||
1126ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev        si == &libdl_info;
1136ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev}
1146ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
115bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartleystatic char ldpaths_buf[LDPATH_BUFSIZE];
116bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartleystatic const char *ldpaths[LDPATH_MAX + 1];
117bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
1184fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischerstatic char ldpreloads_buf[LDPRELOAD_BUFSIZE];
1194fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischerstatic const char *ldpreload_names[LDPRELOAD_MAX + 1];
1204fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
1214fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischerstatic soinfo *preloads[LDPRELOAD_MAX + 1];
1224fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
1231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint debug_verbosity;
1241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int pid;
1251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS
1271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstruct _link_stats linker_stats;
1281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES
1311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectunsigned bitmask[4096];
1321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifndef PT_ARM_EXIDX
1351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define PT_ARM_EXIDX    0x70000001      /* .ARM.exidx segment */
1361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1382e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin#define HOODLUM(name, ret, ...)                                               \
1392e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    ret name __VA_ARGS__                                                      \
1402e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    {                                                                         \
1412e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        char errstr[] = "ERROR: " #name " called from the dynamic linker!\n"; \
1422e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        write(2, errstr, sizeof(errstr));                                     \
1432e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        abort();                                                              \
1442e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    }
1452e85579c34047c305caf15fb0ebe02bf3d001d0eDima ZavinHOODLUM(malloc, void *, (size_t size));
1462e85579c34047c305caf15fb0ebe02bf3d001d0eDima ZavinHOODLUM(free, void, (void *ptr));
1472e85579c34047c305caf15fb0ebe02bf3d001d0eDima ZavinHOODLUM(realloc, void *, (void *ptr, size_t size));
1482e85579c34047c305caf15fb0ebe02bf3d001d0eDima ZavinHOODLUM(calloc, void *, (size_t cnt, size_t size));
1492e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
1500353195f344666256dba474a15c9ba22cf0cccc9Dima Zavinstatic char tmp_err_buf[768];
1512e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavinstatic char __linker_dl_err_buf[768];
1522e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin#define DL_ERR(fmt, x...)                                                     \
1532e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    do {                                                                      \
1545c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner        format_buffer(__linker_dl_err_buf, sizeof(__linker_dl_err_buf),            \
1552e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                 "%s[%d]: " fmt, __func__, __LINE__, ##x);                    \
156d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        ERROR(fmt "\n", ##x);                                                      \
1572e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    } while(0)
1582e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
1592e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavinconst char *linker_get_error(void)
1602e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin{
1612e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    return (const char *)&__linker_dl_err_buf[0];
1622e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin}
1632e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
1641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
1651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * This function is an empty stub where GDB locates a breakpoint to get notified
1661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * about linker activity.
1671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
1681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectextern void __attribute__((noinline)) rtld_db_dlactivity(void);
1691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic struct r_debug _r_debug = {1, NULL, &rtld_db_dlactivity,
1711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                  RT_CONSISTENT, 0};
1721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic struct link_map *r_debug_tail = 0;
1731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1745e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchevstatic pthread_mutex_t _r_debug_lock = PTHREAD_MUTEX_INITIALIZER;
1751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void insert_soinfo_into_debug_map(soinfo * info)
1771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
1781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct link_map * map;
1791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Copy the necessary fields into the debug structure.
1811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
1821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map = &(info->linkmap);
1831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_addr = info->base;
1841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_name = (char*) info->name;
1855cf640c926e7d7b79934c97226433a3dc448e1ebThinker K.F Li    map->l_ld = (uintptr_t)info->dynamic;
1861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Stick the new library at the end of the list.
1881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * gdb tends to care more about libc than it does
1891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * about leaf libraries, and ordering it this way
1901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * reduces the back-and-forth over the wire.
1911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
1921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (r_debug_tail) {
1931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        r_debug_tail->l_next = map;
1941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        map->l_prev = r_debug_tail;
1951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        map->l_next = 0;
1961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    } else {
1971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        _r_debug.r_map = map;
1981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        map->l_prev = 0;
1991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        map->l_next = 0;
2001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    r_debug_tail = map;
2021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2045e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchevstatic void remove_soinfo_from_debug_map(soinfo * info)
2055e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev{
2065e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    struct link_map * map = &(info->linkmap);
2075e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2085e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    if (r_debug_tail == map)
2095e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev        r_debug_tail = map->l_prev;
2105e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2115e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    if (map->l_prev) map->l_prev->l_next = map->l_next;
2125e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    if (map->l_next) map->l_next->l_prev = map->l_prev;
2135e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev}
2145e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid notify_gdb_of_load(soinfo * info)
2161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
2171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (info->flags & FLAG_EXE) {
2181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        // GDB already knows about the main executable
2191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return;
2201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2225e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    pthread_mutex_lock(&_r_debug_lock);
2231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_state = RT_ADD;
2251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    rtld_db_dlactivity();
2261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    insert_soinfo_into_debug_map(info);
2281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_state = RT_CONSISTENT;
2301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    rtld_db_dlactivity();
2311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2325e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    pthread_mutex_unlock(&_r_debug_lock);
2335e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev}
2345e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2355e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchevvoid notify_gdb_of_unload(soinfo * info)
2365e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev{
2375e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    if (info->flags & FLAG_EXE) {
2385e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev        // GDB already knows about the main executable
2395e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev        return;
2405e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    }
2415e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2425e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    pthread_mutex_lock(&_r_debug_lock);
2435e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2445e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    _r_debug.r_state = RT_DELETE;
2455e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    rtld_db_dlactivity();
2465e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2475e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    remove_soinfo_from_debug_map(info);
2485e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2495e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    _r_debug.r_state = RT_CONSISTENT;
2505e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    rtld_db_dlactivity();
2515e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev
2525e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev    pthread_mutex_unlock(&_r_debug_lock);
2531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid notify_gdb_of_libraries()
2561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
2571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_state = RT_ADD;
2581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    rtld_db_dlactivity();
2591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_state = RT_CONSISTENT;
2601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    rtld_db_dlactivity();
2611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *alloc_info(const char *name)
2641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
2651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
2661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(strlen(name) >= SOINFO_NAME_LEN) {
268d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("%5d library name %s too long", pid, name);
269943043583a8f3a8de34970b550a3e8e8a6fb0fb8Doug Kwan        return NULL;
2701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* The freelist is populated when we call free_info(), which in turn is
2731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       done only by dlclose(), which is not likely to be used.
2741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    */
2751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (!freelist) {
2761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(socount == SO_MAX) {
277d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling            DL_ERR("%5d too many libraries when loading %s", pid, name);
2781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return NULL;
2791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
2801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        freelist = sopool + socount++;
2811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        freelist->next = NULL;
2821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si = freelist;
2851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    freelist = freelist->next;
2861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Make sure we get a clean block of soinfo */
2881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    memset(si, 0, sizeof(soinfo));
2891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    strcpy((char*) si->name, name);
2901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    sonext->next = si;
2911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->ba_index = -1; /* by default, prelinked */
2921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->next = NULL;
2931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->refcount = 0;
2941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    sonext = si;
2951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("%5d name %s: allocated soinfo @ %p\n", pid, name, si);
2971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si;
2981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void free_info(soinfo *si)
3011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *prev = NULL, *trav;
3031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("%5d name %s: freeing soinfo @ %p\n", pid, si->name, si);
3051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(trav = solist; trav != NULL; trav = trav->next){
3071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (trav == si)
3081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
3091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        prev = trav;
3101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (trav == NULL) {
3121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* si was not ni solist */
313d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("%5d name %s is not in solist!", pid, si->name);
3141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return;
3151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* prev will never be NULL, because the first entry in solist is
3181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       always the static libdl_info.
3191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    */
3201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    prev->next = si->next;
3211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si == sonext) sonext = prev;
3221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->next = freelist;
3231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    freelist = si;
3241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifndef LINKER_TEXT_BASE
3271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#error "linker's makefile must define LINKER_TEXT_BASE"
3281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
3291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifndef LINKER_AREA_SIZE
3301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#error "linker's makefile must define LINKER_AREA_SIZE"
3311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
3321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define LINKER_BASE ((LINKER_TEXT_BASE) & 0xfff00000)
3331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define LINKER_TOP  (LINKER_BASE + (LINKER_AREA_SIZE))
3341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectconst char *addr_to_name(unsigned addr)
3361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
3381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(si = solist; si != 0; si = si->next){
3401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if((addr >= si->base) && (addr < (si->base + si->size))) {
3411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return si->name;
3421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
3431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if((addr >= LINKER_BASE) && (addr < LINKER_TOP)){
3461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return "linker";
3471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return "";
3501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* For a given PC, find the .so that it belongs to.
3531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns the base address of the .ARM.exidx section
3541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * for that .so, and the number of 8-byte entries
3551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * in that section (via *pcount).
3561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
3571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Intended to be called by libc's __gnu_Unwind_Find_exidx().
3581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
3591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * This function is exposed via dlfcn.c and libdl.so.
3601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
3611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifdef ANDROID_ARM_LINKER
3621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount)
3631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
3651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned addr = (unsigned)pc;
3661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((addr < LINKER_BASE) || (addr >= LINKER_TOP)) {
3681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for (si = solist; si != 0; si = si->next){
3691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if ((addr >= si->base) && (addr < (si->base + si->size))) {
3701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                *pcount = si->ARM_exidx_count;
3711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return (_Unwind_Ptr)(si->base + (unsigned long)si->ARM_exidx);
3721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
3731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
3741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project   *pcount = 0;
3761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return NULL;
3771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
378ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI#elif defined(ANDROID_X86_LINKER) || defined(ANDROID_SH_LINKER)
3791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* Here, we only have to provide a callback to iterate across all the
3801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * loaded libraries. gcc_eh does the rest. */
3811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint
3821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdl_iterate_phdr(int (*cb)(struct dl_phdr_info *info, size_t size, void *data),
3831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                void *data)
3841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
3861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct dl_phdr_info dl_info;
3871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int rv = 0;
3881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (si = solist; si != NULL; si = si->next) {
3901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        dl_info.dlpi_addr = si->linkmap.l_addr;
3911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        dl_info.dlpi_name = si->linkmap.l_name;
3921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        dl_info.dlpi_phdr = si->phdr;
3931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        dl_info.dlpi_phnum = si->phnum;
3941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        rv = cb(&dl_info, sizeof (struct dl_phdr_info), data);
3951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (rv != 0)
3961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
3971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return rv;
3991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
4011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic Elf32_Sym *_elf_lookup(soinfo *si, unsigned hash, const char *name)
4031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
4041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *s;
4051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *symtab = si->symtab;
4061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    const char *strtab = si->strtab;
4071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned n;
4081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE_TYPE(LOOKUP, "%5d SEARCH %s in %s@0x%08x %08x %d\n", pid,
4101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               name, si->name, si->base, hash, hash % si->nbucket);
4111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    n = hash % si->nbucket;
4121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]){
4141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        s = symtab + n;
4151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(strcmp(strtab + s->st_name, name)) continue;
4161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
417e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan            /* only concern ourselves with global and weak symbol definitions */
4181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        switch(ELF32_ST_BIND(s->st_info)){
4191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case STB_GLOBAL:
420e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan        case STB_WEAK:
4211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* no section == undefined */
4221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(s->st_shndx == 0) continue;
4231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(LOOKUP, "%5d FOUND %s in %s (%08x) %d\n", pid,
4251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       name, si->name, s->st_value, s->st_size);
4261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return s;
4271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
4281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
4291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
430943043583a8f3a8de34970b550a3e8e8a6fb0fb8Doug Kwan    return NULL;
4311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned elfhash(const char *_name)
4341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
4351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    const unsigned char *name = (const unsigned char *) _name;
4361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned h = 0, g;
4371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    while(*name) {
4391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        h = (h << 4) + *name++;
4401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        g = h & 0xf0000000;
4411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        h ^= g;
4421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        h ^= g >> 24;
4431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
4441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return h;
4451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic Elf32_Sym *
4486ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev_do_lookup(soinfo *si, const char *name, unsigned *base)
4496ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev{
450943043583a8f3a8de34970b550a3e8e8a6fb0fb8Doug Kwan    unsigned elf_hash = elfhash(name);
4516ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    Elf32_Sym *s;
4526ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    unsigned *d;
4536ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    soinfo *lsi = si;
4544fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    int i;
4556ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
4566ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    /* Look for symbols in the local scope first (the object who is
4576ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev     * searching). This happens with C++ templates on i386 for some
458e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan     * reason.
459e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan     *
460e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan     * Notes on weak symbols:
461e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan     * The ELF specs are ambigious about treatment of weak definitions in
462e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan     * dynamic linking.  Some systems return the first definition found
463e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan     * and some the first non-weak definition.   This is system dependent.
464e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan     * Here we return the first definition found for simplicity.  */
465943043583a8f3a8de34970b550a3e8e8a6fb0fb8Doug Kwan    s = _elf_lookup(si, elf_hash, name);
4666ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    if(s != NULL)
4676ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev        goto done;
4686ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
4694fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    /* Next, look for it in the preloads list */
4704fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    for(i = 0; preloads[i] != NULL; i++) {
4714fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer        lsi = preloads[i];
472f4394458301909a83b7ee7f3b436c038b7235ea8Jean-Baptiste Queru        s = _elf_lookup(lsi, elf_hash, name);
4734fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer        if(s != NULL)
4744fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer            goto done;
4754fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    }
4764fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
4776ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    for(d = si->dynamic; *d; d += 2) {
4786ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev        if(d[0] == DT_NEEDED){
4796ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev            lsi = (soinfo *)d[1];
4806ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev            if (!validate_soinfo(lsi)) {
4816ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                DL_ERR("%5d bad DT_NEEDED pointer in %s",
4826ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                       pid, si->name);
483943043583a8f3a8de34970b550a3e8e8a6fb0fb8Doug Kwan                return NULL;
4846ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev            }
4856ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
4866ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev            DEBUG("%5d %s: looking up %s in %s\n",
4876ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                  pid, si->name, name, lsi->name);
488943043583a8f3a8de34970b550a3e8e8a6fb0fb8Doug Kwan            s = _elf_lookup(lsi, elf_hash, name);
4893cab22c8cf0dcf30718a1452ce9cbb637876cea3Min-su, Kim            if ((s != NULL) && (s->st_shndx != SHN_UNDEF))
4906ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                goto done;
4916ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev        }
4926ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    }
4936ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
4944a9afcb10151b083cd2d75253385615f459172edIliyan Malchev#if ALLOW_SYMBOLS_FROM_MAIN
4954a9afcb10151b083cd2d75253385615f459172edIliyan Malchev    /* If we are resolving relocations while dlopen()ing a library, it's OK for
4964a9afcb10151b083cd2d75253385615f459172edIliyan Malchev     * the library to resolve a symbol that's defined in the executable itself,
4974a9afcb10151b083cd2d75253385615f459172edIliyan Malchev     * although this is rare and is generally a bad idea.
4984a9afcb10151b083cd2d75253385615f459172edIliyan Malchev     */
4994a9afcb10151b083cd2d75253385615f459172edIliyan Malchev    if (somain) {
5004a9afcb10151b083cd2d75253385615f459172edIliyan Malchev        lsi = somain;
5014a9afcb10151b083cd2d75253385615f459172edIliyan Malchev        DEBUG("%5d %s: looking up %s in executable %s\n",
5024a9afcb10151b083cd2d75253385615f459172edIliyan Malchev              pid, si->name, name, lsi->name);
503943043583a8f3a8de34970b550a3e8e8a6fb0fb8Doug Kwan        s = _elf_lookup(lsi, elf_hash, name);
5044a9afcb10151b083cd2d75253385615f459172edIliyan Malchev    }
5054a9afcb10151b083cd2d75253385615f459172edIliyan Malchev#endif
5064a9afcb10151b083cd2d75253385615f459172edIliyan Malchev
5076ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchevdone:
5086ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    if(s != NULL) {
5096ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev        TRACE_TYPE(LOOKUP, "%5d si %s sym %s s->st_value = 0x%08x, "
5106ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                   "found in %s, base = 0x%08x\n",
5116ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                   pid, si->name, name, s->st_value, lsi->name, lsi->base);
5126ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev        *base = lsi->base;
5136ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev        return s;
5146ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    }
5156ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
516943043583a8f3a8de34970b550a3e8e8a6fb0fb8Doug Kwan    return NULL;
5176ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev}
5186ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev
5196ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev/* This is used by dl_sym().  It performs symbol lookup only within the
5206ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev   specified soinfo object and not in any of its dependencies.
5216ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev */
5221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source ProjectElf32_Sym *lookup_in_library(soinfo *si, const char *name)
5231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
524943043583a8f3a8de34970b550a3e8e8a6fb0fb8Doug Kwan    return _elf_lookup(si, elfhash(name), name);
5251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
5261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5276ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev/* This is used by dl_sym().  It performs a global symbol lookup.
5286ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev */
5291698d9ebfc7e27271852a1fdf305a2ac37b3ebe4Matt FischerElf32_Sym *lookup(const char *name, soinfo **found, soinfo *start)
5301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
531943043583a8f3a8de34970b550a3e8e8a6fb0fb8Doug Kwan    unsigned elf_hash = elfhash(name);
5321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *s = NULL;
5331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
5341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5351698d9ebfc7e27271852a1fdf305a2ac37b3ebe4Matt Fischer    if(start == NULL) {
5361698d9ebfc7e27271852a1fdf305a2ac37b3ebe4Matt Fischer        start = solist;
5371698d9ebfc7e27271852a1fdf305a2ac37b3ebe4Matt Fischer    }
5381698d9ebfc7e27271852a1fdf305a2ac37b3ebe4Matt Fischer
5391698d9ebfc7e27271852a1fdf305a2ac37b3ebe4Matt Fischer    for(si = start; (s == NULL) && (si != NULL); si = si->next)
5401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    {
5416ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev        if(si->flags & FLAG_ERROR)
5421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            continue;
543e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan        s = _elf_lookup(si, elf_hash, name);
5441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (s != NULL) {
5459ea64da6c511e8f9f4edae4c10c20879957631abIliyan Malchev            *found = si;
5461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
5471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
5481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
5491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5506ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev    if(s != NULL) {
5511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE_TYPE(LOOKUP, "%5d %s s->st_value = 0x%08x, "
5521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   "si->base = 0x%08x\n", pid, name, s->st_value, si->base);
5531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return s;
5541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
5551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
556943043583a8f3a8de34970b550a3e8e8a6fb0fb8Doug Kwan    return NULL;
5571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
5581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
559e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischersoinfo *find_containing_library(void *addr)
560e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer{
561e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer    soinfo *si;
562e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer
563e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer    for(si = solist; si != NULL; si = si->next)
564e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer    {
565e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer        if((unsigned)addr >= si->base && (unsigned)addr - si->base < si->size) {
566e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer            return si;
567e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer        }
568e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer    }
569e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer
570e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer    return NULL;
571e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer}
572e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer
573e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt FischerElf32_Sym *find_containing_symbol(void *addr, soinfo *si)
574e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer{
575e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer    unsigned int i;
576e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer    unsigned soaddr = (unsigned)addr - si->base;
577e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer
578e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer    /* Search the library's symbol table for any defined symbol which
579e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer     * contains this address */
580e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer    for(i=0; i<si->nchain; i++) {
581e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer        Elf32_Sym *sym = &si->symtab[i];
582e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer
583e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer        if(sym->st_shndx != SHN_UNDEF &&
584e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer           soaddr >= sym->st_value &&
585e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer           soaddr < sym->st_value + sym->st_size) {
586e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer            return sym;
587e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer        }
588e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer    }
589e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer
590e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer    return NULL;
591e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer}
592e2a8b1fd19fb3a8ead2ba28ddba27be19fa978b5Matt Fischer
5931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
5941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void dump(soinfo *si)
5951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
5961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *s = si->symtab;
5971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned n;
5981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(n = 0; n < si->nchain; n++) {
6001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("%5d %04d> %08x: %02x %04x %08x %08x %s\n", pid, n, s,
6011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               s->st_info, s->st_shndx, s->st_value, s->st_size,
6021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               si->strtab + s->st_name);
6031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        s++;
6041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
6061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
6071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic const char *sopaths[] = {
609fedbcde6ef552e84bf7ce7598bca7dddf1722d6aBrian Swetland    "/vendor/lib",
6101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    "/system/lib",
6111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    0
6121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project};
6131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int _open_lib(const char *name)
6151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
6161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int fd;
6171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct stat filestat;
6181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((stat(name, &filestat) >= 0) && S_ISREG(filestat.st_mode)) {
6201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if ((fd = open(name, O_RDONLY)) >= 0)
6211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return fd;
6221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
6251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
6261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int open_library(const char *name)
6281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
6291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int fd;
6301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    char buf[512];
6311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    const char **path;
632bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    int n;
6331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d opening %s ]\n", pid, name);
6351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(name == 0) return -1;
6371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(strlen(name) > 256) return -1;
6381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((name[0] == '/') && ((fd = _open_lib(name)) >= 0))
6401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return fd;
6411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
642bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    for (path = ldpaths; *path; path++) {
6435c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner        n = format_buffer(buf, sizeof(buf), "%s/%s", *path, name);
644bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        if (n < 0 || n >= (int)sizeof(buf)) {
645bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            WARN("Ignoring very long library path: %s/%s\n", *path, name);
646bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            continue;
647bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        }
648bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        if ((fd = _open_lib(buf)) >= 0)
649bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            return fd;
650bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    }
6511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (path = sopaths; *path; path++) {
6525c734644eebf8d01be1e86cbe20a111a5c5a2738David 'Digit' Turner        n = format_buffer(buf, sizeof(buf), "%s/%s", *path, name);
653bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        if (n < 0 || n >= (int)sizeof(buf)) {
654bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            WARN("Ignoring very long library path: %s/%s\n", *path, name);
655bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            continue;
656bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        }
6571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if ((fd = _open_lib(buf)) >= 0)
6581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return fd;
6591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
6621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
6631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* temporary space for holding the first page of the shared lib
6651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * which contains the elf header (with the pht). */
6661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned char __header[PAGE_SIZE];
6671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecttypedef struct {
6691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    long mmap_addr;
6701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    char tag[4]; /* 'P', 'R', 'E', ' ' */
6711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} prelink_info_t;
6721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* Returns the requested base address if the library is prelinked,
6741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * and 0 otherwise.  */
6751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned long
6761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectis_prelinked(int fd, const char *name)
6771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
6781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    off_t sz;
6791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    prelink_info_t info;
6801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    sz = lseek(fd, -sizeof(prelink_info_t), SEEK_END);
6821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (sz < 0) {
683d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("lseek() failed!");
6841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return 0;
6851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (read(fd, &info, sizeof(info)) != sizeof(info)) {
6881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        WARN("Could not read prelink_info_t structure for `%s`\n", name);
6891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return 0;
6901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (strncmp(info.tag, "PRE ", 4)) {
6931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        WARN("`%s` is not a prelinked library\n", name);
6941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return 0;
6951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return (unsigned long)info.mmap_addr;
6981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
6991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* verify_elf_object
7011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      Verifies if the object @ base is a valid ELF object
7021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
7031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Args:
7041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
7051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns:
7061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *       0 on success
7071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      -1 if no valid ELF object is found @ base.
7081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
7091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int
7101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectverify_elf_object(void *base, const char *name)
7111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
7121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Ehdr *hdr = (Elf32_Ehdr *) base;
7131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (hdr->e_ident[EI_MAG0] != ELFMAG0) return -1;
7151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (hdr->e_ident[EI_MAG1] != ELFMAG1) return -1;
7161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (hdr->e_ident[EI_MAG2] != ELFMAG2) return -1;
7171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (hdr->e_ident[EI_MAG3] != ELFMAG3) return -1;
7181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* TODO: Should we verify anything else in the header? */
7201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
7221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
7231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* get_lib_extents
7261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      Retrieves the base (*base) address where the ELF object should be
7271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      mapped and its overall memory size (*total_sz).
7281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
7291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Args:
7301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      fd: Opened file descriptor for the library
7311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      name: The name of the library
7321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      _hdr: Pointer to the header page of the library
7331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      total_sz: Total size of the memory that should be allocated for
7341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *                this library
7351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
7361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns:
7371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      -1 if there was an error while trying to get the lib extents.
7381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *         The possible reasons are:
7391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *             - Could not determine if the library was prelinked.
7401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *             - The library provided is not a valid ELF object
7411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *       0 if the library did not request a specific base offset (normal
7421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *         for non-prelinked libs)
7431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     > 0 if the library requests a specific address to be mapped to.
7441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *         This indicates a pre-linked library.
7451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
7461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned
7471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectget_lib_extents(int fd, const char *name, void *__hdr, unsigned *total_sz)
7481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
7491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned req_base;
7501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned min_vaddr = 0xffffffff;
7511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned max_vaddr = 0;
7521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *_hdr = (unsigned char *)__hdr;
7531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Ehdr *ehdr = (Elf32_Ehdr *)_hdr;
7541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Phdr *phdr;
7551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int cnt;
7561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d Computing extents for '%s'. ]\n", pid, name);
7581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (verify_elf_object(_hdr, name) < 0) {
759d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("%5d - %s is not a valid ELF object", pid, name);
7601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return (unsigned)-1;
7611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
7621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    req_base = (unsigned) is_prelinked(fd, name);
7641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (req_base == (unsigned)-1)
7651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return -1;
7661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    else if (req_base != 0) {
7671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d - Prelinked library '%s' requesting base @ 0x%08x ]\n",
7681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, name, req_base);
7691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    } else {
7701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d - Non-prelinked library '%s' found. ]\n", pid, name);
7711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
7721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    phdr = (Elf32_Phdr *)(_hdr + ehdr->e_phoff);
7741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* find the min/max p_vaddrs from all the PT_LOAD segments so we can
7761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * get the range. */
7771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (cnt = 0; cnt < ehdr->e_phnum; ++cnt, ++phdr) {
7781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (phdr->p_type == PT_LOAD) {
7791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if ((phdr->p_vaddr + phdr->p_memsz) > max_vaddr)
7801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                max_vaddr = phdr->p_vaddr + phdr->p_memsz;
7811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (phdr->p_vaddr < min_vaddr)
7821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                min_vaddr = phdr->p_vaddr;
7831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
7841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
7851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((min_vaddr == 0xffffffff) && (max_vaddr == 0)) {
787d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("%5d - No loadable segments found in %s.", pid, name);
7881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return (unsigned)-1;
7891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
7901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* truncate min_vaddr down to page boundary */
7921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    min_vaddr &= ~PAGE_MASK;
7931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* round max_vaddr up to the next page */
7951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    max_vaddr = (max_vaddr + PAGE_SIZE - 1) & ~PAGE_MASK;
7961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    *total_sz = (max_vaddr - min_vaddr);
7981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return (unsigned)req_base;
7991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
8001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* alloc_mem_region
8021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
8031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     This function reserves a chunk of memory to be used for mapping in
8041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     the shared library. We reserve the entire memory region here, and
8051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     then the rest of the linker will relocate the individual loadable
8061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     segments into the correct locations within this memory range.
8071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
8081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Args:
8091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     si->base: The requested base of the allocation. If 0, a sane one will be
8101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *               chosen in the range LIBBASE <= base < LIBLAST.
8111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     si->size: The size of the allocation.
8121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
8131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns:
8141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     -1 on failure, and 0 on success.  On success, si->base will contain
8151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     the virtual address at which the library will be mapped.
8161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
8171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int reserve_mem_region(soinfo *si)
8191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
8201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    void *base = mmap((void *)si->base, si->size, PROT_READ | PROT_EXEC,
8211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
8221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (base == MAP_FAILED) {
8232e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("%5d can NOT map (%sprelinked) library '%s' at 0x%08x "
824d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling              "as requested, will try general pool: %d (%s)",
8251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, (si->base ? "" : "non-"), si->name, si->base,
8261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              errno, strerror(errno));
8271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return -1;
8281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    } else if (base != (void *)si->base) {
8292e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("OOPS: %5d %sprelinked library '%s' mapped at 0x%08x, "
830d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling              "not at 0x%08x", pid, (si->base ? "" : "non-"),
8311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              si->name, (unsigned)base, si->base);
8321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        munmap(base, si->size);
8331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return -1;
8341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
8351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
8361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
8371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int
8391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectalloc_mem_region(soinfo *si)
8401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
8411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->base) {
8421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* Attempt to mmap a prelinked library. */
8431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->ba_index = -1;
8441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return reserve_mem_region(si);
8451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
8461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* This is not a prelinked library, so we attempt to allocate space
8481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       for it from the buddy allocator, which manages the area between
8491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       LIBBASE and LIBLAST.
8501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    */
851e100f52f4ad1b70762bbcc5ad9828bd258917ee5Iliyan Malchev    si->ba_index = ba_allocate(&ba_nonprelink, si->size);
8521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si->ba_index >= 0) {
853e100f52f4ad1b70762bbcc5ad9828bd258917ee5Iliyan Malchev        si->base = ba_start_addr(&ba_nonprelink, si->ba_index);
8541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        PRINT("%5d mapping library '%s' at %08x (index %d) " \
8551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              "through buddy allocator.\n",
8561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, si->name, si->base, si->ba_index);
8571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (reserve_mem_region(si) < 0) {
858e100f52f4ad1b70762bbcc5ad9828bd258917ee5Iliyan Malchev            ba_free(&ba_nonprelink, si->ba_index);
8591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->ba_index = -1;
8601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->base = 0;
8611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            goto err;
8621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
8631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return 0;
8641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
8651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecterr:
867d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling    DL_ERR("OOPS: %5d cannot map library '%s'. no vspace available.",
8681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          pid, si->name);
8691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
8701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
8711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define MAYBE_MAP_FLAG(x,from,to)    (((x) & (from)) ? (to) : 0)
8731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define PFLAGS_TO_PROT(x)            (MAYBE_MAP_FLAG((x), PF_X, PROT_EXEC) | \
8741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                      MAYBE_MAP_FLAG((x), PF_R, PROT_READ) | \
8751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                      MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE))
8761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* load_segments
8771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
8781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     This function loads all the loadable (PT_LOAD) segments into memory
8791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     at their appropriate memory offsets off the base address.
8801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
8811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Args:
8821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     fd: Open file descriptor to the library to load.
8831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     header: Pointer to a header page that contains the ELF header.
8841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *             This is needed since we haven't mapped in the real file yet.
8851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     si: ptr to soinfo struct describing the shared object.
8861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
8871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns:
8881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     0 on success, -1 on failure.
8891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
8901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int
8911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectload_segments(int fd, void *header, soinfo *si)
8921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
8931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Ehdr *ehdr = (Elf32_Ehdr *)header;
8941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Phdr *phdr = (Elf32_Phdr *)((unsigned char *)header + ehdr->e_phoff);
8951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *base = (unsigned char *)si->base;
8961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int cnt;
8971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned len;
8981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *tmp;
8991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *pbase;
9001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *extra_base;
9011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned extra_len;
9021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned total_sz = 0;
9031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->wrprotect_start = 0xffffffff;
9051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->wrprotect_end = 0;
9061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d - Begin loading segments for '%s' @ 0x%08x ]\n",
9081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          pid, si->name, (unsigned)si->base);
9091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Now go through all the PT_LOAD segments and map them into memory
9101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * at the appropriate locations. */
9111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (cnt = 0; cnt < ehdr->e_phnum; ++cnt, ++phdr) {
9121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (phdr->p_type == PT_LOAD) {
9131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG_DUMP_PHDR(phdr, "PT_LOAD", pid);
9141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* we want to map in the segment on a page boundary */
9151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            tmp = base + (phdr->p_vaddr & (~PAGE_MASK));
9161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* add the # of bytes we masked off above to the total length. */
9171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            len = phdr->p_filesz + (phdr->p_vaddr & PAGE_MASK);
9181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE("[ %d - Trying to load segment from '%s' @ 0x%08x "
9201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  "(0x%08x). p_vaddr=0x%08x p_offset=0x%08x ]\n", pid, si->name,
9211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  (unsigned)tmp, len, phdr->p_vaddr, phdr->p_offset);
9221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            pbase = mmap(tmp, len, PFLAGS_TO_PROT(phdr->p_flags),
9231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                         MAP_PRIVATE | MAP_FIXED, fd,
9241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                         phdr->p_offset & (~PAGE_MASK));
9251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (pbase == MAP_FAILED) {
9262e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                DL_ERR("%d failed to map segment from '%s' @ 0x%08x (0x%08x). "
927d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling                      "p_vaddr=0x%08x p_offset=0x%08x", pid, si->name,
9281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      (unsigned)tmp, len, phdr->p_vaddr, phdr->p_offset);
9291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                goto fail;
9301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
9311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* If 'len' didn't end on page boundary, and it's a writable
9331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * segment, zero-fill the rest. */
9341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if ((len & PAGE_MASK) && (phdr->p_flags & PF_W))
9351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                memset((void *)(pbase + len), 0, PAGE_SIZE - (len & PAGE_MASK));
9361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* Check to see if we need to extend the map for this segment to
9381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * cover the diff between filesz and memsz (i.e. for bss).
9391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *
9401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  base           _+---------------------+  page boundary
9411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  .                     .
9421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  |                     |
9431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  .                     .
9441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  pbase          _+---------------------+  page boundary
9451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  |                     |
9461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  .                     .
9471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  base + p_vaddr _|                     |
9481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  . \          \        .
9491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  . | filesz   |        .
9501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  pbase + len    _| /          |        |
9511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *     <0 pad>      .            .        .
9521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  extra_base     _+------------|--------+  page boundary
9531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               /  .            .        .
9541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               |  .            .        .
9551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               |  +------------|--------+  page boundary
9561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  extra_len->  |  |            |        |
9571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               |  .            | memsz  .
9581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               |  .            |        .
9591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               \ _|            /        |
9601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  .                     .
9611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  |                     |
9621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                 _+---------------------+  page boundary
9631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             */
9641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            tmp = (unsigned char *)(((unsigned)pbase + len + PAGE_SIZE - 1) &
9651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                    (~PAGE_MASK));
9661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (tmp < (base + phdr->p_vaddr + phdr->p_memsz)) {
9671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                extra_len = base + phdr->p_vaddr + phdr->p_memsz - tmp;
9681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                TRACE("[ %5d - Need to extend segment from '%s' @ 0x%08x "
9691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      "(0x%08x) ]\n", pid, si->name, (unsigned)tmp, extra_len);
9701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* map in the extra page(s) as anonymous into the range.
9711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * This is probably not necessary as we already mapped in
9721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * the entire region previously, but we just want to be
9731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * sure. This will also set the right flags on the region
9741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * (though we can probably accomplish the same thing with
9751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * mprotect).
9761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 */
9771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                extra_base = mmap((void *)tmp, extra_len,
9781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                  PFLAGS_TO_PROT(phdr->p_flags),
9791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                  MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS,
9801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                  -1, 0);
9811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (extra_base == MAP_FAILED) {
9822e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                    DL_ERR("[ %5d - failed to extend segment from '%s' @ 0x%08x"
983d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling                           " (0x%08x) ]", pid, si->name, (unsigned)tmp,
9841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                          extra_len);
9851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    goto fail;
9861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                }
9871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* TODO: Check if we need to memset-0 this region.
9881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * Anonymous mappings are zero-filled copy-on-writes, so we
9891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * shouldn't need to. */
9901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                TRACE("[ %5d - Segment from '%s' extended @ 0x%08x "
9911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      "(0x%08x)\n", pid, si->name, (unsigned)extra_base,
9921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      extra_len);
9931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
9941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* set the len here to show the full extent of the segment we
9951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * just loaded, mostly for debugging */
9961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            len = (((unsigned)base + phdr->p_vaddr + phdr->p_memsz +
9971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    PAGE_SIZE - 1) & (~PAGE_MASK)) - (unsigned)pbase;
9981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE("[ %5d - Successfully loaded segment from '%s' @ 0x%08x "
9991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  "(0x%08x). p_vaddr=0x%08x p_offset=0x%08x\n", pid, si->name,
10001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  (unsigned)pbase, len, phdr->p_vaddr, phdr->p_offset);
10011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            total_sz += len;
10021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* Make the section writable just in case we'll have to write to
10031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * it during relocation (i.e. text segment). However, we will
10041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * remember what range of addresses should be write protected.
10051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *
10061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             */
10071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (!(phdr->p_flags & PF_W)) {
10081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if ((unsigned)pbase < si->wrprotect_start)
10091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    si->wrprotect_start = (unsigned)pbase;
10101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (((unsigned)pbase + len) > si->wrprotect_end)
10111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    si->wrprotect_end = (unsigned)pbase + len;
10121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                mprotect(pbase, len,
10131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                         PFLAGS_TO_PROT(phdr->p_flags) | PROT_WRITE);
10141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
10151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } else if (phdr->p_type == PT_DYNAMIC) {
10161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG_DUMP_PHDR(phdr, "PT_DYNAMIC", pid);
10171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* this segment contains the dynamic linking information */
10181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->dynamic = (unsigned *)(base + phdr->p_vaddr);
10191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } else {
10201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifdef ANDROID_ARM_LINKER
10211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (phdr->p_type == PT_ARM_EXIDX) {
10221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                DEBUG_DUMP_PHDR(phdr, "PT_ARM_EXIDX", pid);
10231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* exidx entries (used for stack unwinding) are 8 bytes each.
10241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 */
10251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->ARM_exidx = (unsigned *)phdr->p_vaddr;
10261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->ARM_exidx_count = phdr->p_memsz / 8;
10271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
10281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
10291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
10301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
10321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Sanity check */
10341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (total_sz > si->size) {
10352e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        DL_ERR("%5d - Total length (0x%08x) of mapped segments from '%s' is "
1036d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling              "greater than what was allocated (0x%08x). THIS IS BAD!",
10371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, total_sz, si->name, si->size);
10381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
10391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
10401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d - Finish loading segments for '%s' @ 0x%08x. "
10421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          "Total memory footprint: 0x%08x bytes ]\n", pid, si->name,
10431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          (unsigned)si->base, si->size);
10441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
10451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectfail:
10471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* We can just blindly unmap the entire region even though some things
10481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * were mapped in originally with anonymous and others could have been
10491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * been mapped in from the file before we failed. The kernel will unmap
10501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * all the pages in the range, irrespective of how they got there.
10511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
10521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    munmap((void *)si->base, si->size);
10531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags |= FLAG_ERROR;
10541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
10551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
10561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* TODO: Implement this to take care of the fact that Android ARM
10581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ELF objects shove everything into a single loadable segment that has the
10591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * write bit set. wr_offset is then used to set non-(data|bss) pages to be
10601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * non-writable.
10611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
10621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
10631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned
10641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectget_wr_offset(int fd, const char *name, Elf32_Ehdr *ehdr)
10651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
10661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Shdr *shdr_start;
10671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Shdr *shdr;
10681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int shdr_sz = ehdr->e_shnum * sizeof(Elf32_Shdr);
10691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int cnt;
10701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned wr_offset = 0xffffffff;
10711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    shdr_start = mmap(0, shdr_sz, PROT_READ, MAP_PRIVATE, fd,
10731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      ehdr->e_shoff & (~PAGE_MASK));
10741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (shdr_start == MAP_FAILED) {
10751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        WARN("%5d - Could not read section header info from '%s'. Will not "
10761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             "not be able to determine write-protect offset.\n", pid, name);
10771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return (unsigned)-1;
10781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
10791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(cnt = 0, shdr = shdr_start; cnt < ehdr->e_shnum; ++cnt, ++shdr) {
10811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if ((shdr->sh_type != SHT_NULL) && (shdr->sh_flags & SHF_WRITE) &&
10821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            (shdr->sh_addr < wr_offset)) {
10831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            wr_offset = shdr->sh_addr;
10841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
10851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
10861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    munmap(shdr_start, shdr_sz);
10881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return wr_offset;
10891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
10901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
10911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *
10931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectload_library(const char *name)
10941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
10951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int fd = open_library(name);
10961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int cnt;
10971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned ext_sz;
10981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned req_base;
1099fde8642fc43bdd224e43e5ee9583a49a758fb03cErik Gilling    const char *bname;
11001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si = NULL;
11011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Ehdr *hdr;
11021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11032e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    if(fd == -1) {
1104d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("Library '%s' not found", name);
11051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return NULL;
11062e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    }
11071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* We have to read the ELF header to figure out what to do with this image
11091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
11101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (lseek(fd, 0, SEEK_SET) < 0) {
1111d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("lseek() failed!");
11121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
11131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
11141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((cnt = read(fd, &__header[0], PAGE_SIZE)) < 0) {
1116d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("read() failed!");
11171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
11181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
11191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Parse the ELF header and get the size of the memory footprint for
11211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * the library */
11221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    req_base = get_lib_extents(fd, name, &__header[0], &ext_sz);
11231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (req_base == (unsigned)-1)
11241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
11251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d - '%s' (%s) wants base=0x%08x sz=0x%08x ]\n", pid, name,
11261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          (req_base ? "prelinked" : "not pre-linked"), req_base, ext_sz);
11271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Now configure the soinfo struct where we'll store all of our data
11291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * for the ELF object. If the loading fails, we waste the entry, but
11301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * same thing would happen if we failed during linking. Configuring the
11311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * soinfo struct here is a lot more convenient.
11321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
1133fde8642fc43bdd224e43e5ee9583a49a758fb03cErik Gilling    bname = strrchr(name, '/');
1134fde8642fc43bdd224e43e5ee9583a49a758fb03cErik Gilling    si = alloc_info(bname ? bname + 1 : name);
11351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si == NULL)
11361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
11371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Carve out a chunk of memory where we will map in the individual
11391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * segments */
11401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->base = req_base;
11411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->size = ext_sz;
11421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags = 0;
11431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->entry = 0;
11441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->dynamic = (unsigned *)-1;
11451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (alloc_mem_region(si) < 0)
11461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
11471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d allocated memory for %s @ %p (0x%08x) ]\n",
11491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          pid, name, (void *)si->base, (unsigned) ext_sz);
11501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Now actually load the library's segments into right places in memory */
11521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (load_segments(fd, &__header[0], si) < 0) {
11531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (si->ba_index >= 0) {
1154e100f52f4ad1b70762bbcc5ad9828bd258917ee5Iliyan Malchev            ba_free(&ba_nonprelink, si->ba_index);
11551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->ba_index = -1;
11561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
11571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
11581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
11591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* this might not be right. Technically, we don't even need this info
11611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * once we go through 'load_segments'. */
11621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    hdr = (Elf32_Ehdr *)si->base;
11631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->phdr = (Elf32_Phdr *)((unsigned char *)si->base + hdr->e_phoff);
11641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->phnum = hdr->e_phnum;
11651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /**/
11661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    close(fd);
11681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si;
11691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectfail:
11711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si) free_info(si);
11721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    close(fd);
11731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return NULL;
11741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
11751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *
11771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectinit_library(soinfo *si)
11781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
11791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned wr_offset = 0xffffffff;
11801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* At this point we know that whatever is loaded @ base is a valid ELF
11821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * shared library whose segments are properly mapped in. */
11831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d init_library base=0x%08x sz=0x%08x name='%s') ]\n",
11841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          pid, si->base, si->size, si->name);
11851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->base < LIBBASE || si->base >= LIBLAST)
11871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->flags |= FLAG_PRELINKED;
11881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(link_image(si, wr_offset)) {
11901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* We failed to link.  However, we can only restore libbase
11911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ** if no additional libraries have moved it since we updated it.
11921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            */
11931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        munmap((void *)si->base, si->size);
11941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return NULL;
11951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
11961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si;
11981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
11991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectsoinfo *find_library(const char *name)
12011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
12021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
12036774809b6249d9d4efd982b6e3ca377c84482d9aDavid 'Digit' Turner    const char *bname;
12046774809b6249d9d4efd982b6e3ca377c84482d9aDavid 'Digit' Turner
12056774809b6249d9d4efd982b6e3ca377c84482d9aDavid 'Digit' Turner#if ALLOW_SYMBOLS_FROM_MAIN
12066774809b6249d9d4efd982b6e3ca377c84482d9aDavid 'Digit' Turner    if (name == NULL)
12076774809b6249d9d4efd982b6e3ca377c84482d9aDavid 'Digit' Turner        return somain;
12086774809b6249d9d4efd982b6e3ca377c84482d9aDavid 'Digit' Turner#else
12096774809b6249d9d4efd982b6e3ca377c84482d9aDavid 'Digit' Turner    if (name == NULL)
12106774809b6249d9d4efd982b6e3ca377c84482d9aDavid 'Digit' Turner        return NULL;
12116774809b6249d9d4efd982b6e3ca377c84482d9aDavid 'Digit' Turner#endif
12126774809b6249d9d4efd982b6e3ca377c84482d9aDavid 'Digit' Turner
12136774809b6249d9d4efd982b6e3ca377c84482d9aDavid 'Digit' Turner    bname = strrchr(name, '/');
1214fde8642fc43bdd224e43e5ee9583a49a758fb03cErik Gilling    bname = bname ? bname + 1 : name;
12151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(si = solist; si != 0; si = si->next){
1217fde8642fc43bdd224e43e5ee9583a49a758fb03cErik Gilling        if(!strcmp(bname, si->name)) {
121830eb40241c612a7ddbd21c4daa4e7bbfd9d5e89fErik Gilling            if(si->flags & FLAG_ERROR) {
121930eb40241c612a7ddbd21c4daa4e7bbfd9d5e89fErik Gilling                DL_ERR("%5d '%s' failed to load previously", pid, bname);
122030eb40241c612a7ddbd21c4daa4e7bbfd9d5e89fErik Gilling                return NULL;
122130eb40241c612a7ddbd21c4daa4e7bbfd9d5e89fErik Gilling            }
12221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(si->flags & FLAG_LINKED) return si;
1223d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling            DL_ERR("OOPS: %5d recursive link to '%s'", pid, si->name);
12242e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin            return NULL;
12251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
12261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
12271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d '%s' has not been loaded yet.  Locating...]\n", pid, name);
12291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si = load_library(name);
12301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si == NULL)
12311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return NULL;
12321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return init_library(si);
12331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
12341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* TODO:
12361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   notify gdb of unload
12371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   for non-prelinked libraries, find a way to decrement libbase
12381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
12391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void call_destructors(soinfo *si);
12401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectunsigned unload_library(soinfo *si)
12411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
12421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned *d;
12431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->refcount == 1) {
12441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("%5d unloading '%s'\n", pid, si->name);
12451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        call_destructors(si);
12461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for(d = si->dynamic; *d; d += 2) {
12481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(d[0] == DT_NEEDED){
12496ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                soinfo *lsi = (soinfo *)d[1];
12506ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                d[1] = 0;
12516ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                if (validate_soinfo(lsi)) {
12526ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                    TRACE("%5d %s needs to unload %s\n", pid,
12536ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                          si->name, lsi->name);
12541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    unload_library(lsi);
12556ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                }
12561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                else
12576ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                    DL_ERR("%5d %s: could not unload dependent library",
12586ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev                           pid, si->name);
12591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
12601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
12611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        munmap((char *)si->base, si->size);
12631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (si->ba_index >= 0) {
12641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            PRINT("%5d releasing library '%s' address space at %08x "\
12651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  "through buddy allocator.\n",
12661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->base);
1267e100f52f4ad1b70762bbcc5ad9828bd258917ee5Iliyan Malchev            ba_free(&ba_nonprelink, si->ba_index);
12681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
12695e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev        notify_gdb_of_unload(si);
12701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        free_info(si);
12711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->refcount = 0;
12721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
12731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    else {
12741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->refcount--;
12751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        PRINT("%5d not unloading '%s', decrementing refcount to %d\n",
12761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, si->name, si->refcount);
12771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
12781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si->refcount;
12791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
12801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* TODO: don't use unsigned for addrs below. It works, but is not
12821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ideal. They should probably be either uint32_t, Elf32_Addr, or unsigned
12831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * long.
12841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
12851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int reloc_library(soinfo *si, Elf32_Rel *rel, unsigned count)
12861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
12871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *symtab = si->symtab;
12881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    const char *strtab = si->strtab;
12891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *s;
12901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned base;
12911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Rel *start = rel;
12921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned idx;
12931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (idx = 0; idx < count; ++idx) {
12951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned type = ELF32_R_TYPE(rel->r_info);
12961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned sym = ELF32_R_SYM(rel->r_info);
12971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned reloc = (unsigned)(rel->r_offset + si->base);
12981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned sym_addr = 0;
12991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        char *sym_name = NULL;
13001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        DEBUG("%5d Processing '%s' relocation at index %d\n", pid,
13021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              si->name, idx);
13031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(sym != 0) {
1304d1b40d8c69dfca94185ea9231f6cb16f70c02e39Dima Zavin            sym_name = (char *)(strtab + symtab[sym].st_name);
1305d1b40d8c69dfca94185ea9231f6cb16f70c02e39Dima Zavin            s = _do_lookup(si, sym_name, &base);
1306e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan            if(s == NULL) {
1307e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                /* We only allow an undefined symbol if this is a weak
1308e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                   reference..   */
1309e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                s = &symtab[sym];
1310e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                if (ELF32_ST_BIND(s->st_info) != STB_WEAK) {
1311e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                    DL_ERR("%5d cannot locate '%s'...\n", pid, sym_name);
1312e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                    return -1;
1313e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                }
1314e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan
1315e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                /* IHI0044C AAELF 4.5.1.1:
1316e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan
1317e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                   Libraries are not searched to resolve weak references.
1318e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                   It is not an error for a weak reference to remain
1319e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                   unsatisfied.
1320e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan
1321e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                   During linking, the value of an undefined weak reference is:
1322e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                   - Zero if the relocation type is absolute
1323e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                   - The address of the place if the relocation is pc-relative
1324e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                   - The address of nominial base address if the relocation
1325e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                     type is base-relative.
1326e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                  */
1327e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan
1328e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                switch (type) {
1329e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan#if defined(ANDROID_ARM_LINKER)
1330e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                case R_ARM_JUMP_SLOT:
1331e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                case R_ARM_GLOB_DAT:
1332e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                case R_ARM_ABS32:
1333e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                case R_ARM_RELATIVE:    /* Don't care. */
1334e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                case R_ARM_NONE:        /* Don't care. */
1335e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan#elif defined(ANDROID_X86_LINKER)
1336e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                case R_386_JUMP_SLOT:
1337e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                case R_386_GLOB_DAT:
1338e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                case R_386_32:
1339e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                case R_386_RELATIVE:    /* Dont' care. */
1340e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan#endif /* ANDROID_*_LINKER */
1341e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                    /* sym_addr was initialized to be zero above or relocation
1342e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                       code below does not care about value of sym_addr.
1343e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                       No need to do anything.  */
1344e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                    break;
1345e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan
1346e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan#if defined(ANDROID_X86_LINKER)
1347e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                case R_386_PC32:
1348e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                    sym_addr = reloc;
1349e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                    break;
1350e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan#endif /* ANDROID_X86_LINKER */
1351e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan
1352e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan#if defined(ANDROID_ARM_LINKER)
1353e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                case R_ARM_COPY:
1354e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                    /* Fall through.  Can't really copy if weak symbol is
1355e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                       not found in run-time.  */
1356e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan#endif /* ANDROID_ARM_LINKER */
1357e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                default:
1358e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                    DL_ERR("%5d unknown weak reloc type %d @ %p (%d)\n",
1359e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                                 pid, type, rel, (int) (rel - start));
1360e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                    return -1;
1361e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                }
1362e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan            } else {
1363e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                /* We got a definition.  */
13641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
13651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if((base == 0) && (si->base != 0)){
13661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    /* linking from libraries to main image is bad */
1367d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling                DL_ERR("%5d cannot locate '%s'...",
13681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       pid, strtab + symtab[sym].st_name);
13691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return -1;
13701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
13711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1372e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan                sym_addr = (unsigned)(s->st_value + base);
1373e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan	    }
13741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_SYMBOL);
13751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } else {
1376e823807dc2fb5f2d44cd00d75c10ddd9f5e93beaDoug Kwan            s = NULL;
13771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
13781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* TODO: This is ugly. Split up the relocations by arch into
13801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * different files.
13811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
13821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        switch(type){
13831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if defined(ANDROID_ARM_LINKER)
13841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_JUMP_SLOT:
13851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
13861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
13871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO JMP_SLOT %08x <- %08x %s\n", pid,
13881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
13891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) = sym_addr;
13901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
13911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_GLOB_DAT:
13921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
13931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
13941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO GLOB_DAT %08x <- %08x %s\n", pid,
13951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
13961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) = sym_addr;
13971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
13981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_ABS32:
13991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
14001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
14011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO ABS %08x <- %08x %s\n", pid,
14021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
14031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) += sym_addr;
14041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
140534ea5117dbeba41ae5dfdfb2c2ec8cae23388b66David 'Digit' Turner        case R_ARM_REL32:
140634ea5117dbeba41ae5dfdfb2c2ec8cae23388b66David 'Digit' Turner            COUNT_RELOC(RELOC_RELATIVE);
140734ea5117dbeba41ae5dfdfb2c2ec8cae23388b66David 'Digit' Turner            MARK(rel->r_offset);
140834ea5117dbeba41ae5dfdfb2c2ec8cae23388b66David 'Digit' Turner            TRACE_TYPE(RELO, "%5d RELO REL32 %08x <- %08x - %08x %s\n", pid,
140934ea5117dbeba41ae5dfdfb2c2ec8cae23388b66David 'Digit' Turner                       reloc, sym_addr, rel->r_offset, sym_name);
141034ea5117dbeba41ae5dfdfb2c2ec8cae23388b66David 'Digit' Turner            *((unsigned*)reloc) += sym_addr - rel->r_offset;
141134ea5117dbeba41ae5dfdfb2c2ec8cae23388b66David 'Digit' Turner            break;
14121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#elif defined(ANDROID_X86_LINKER)
14131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_JUMP_SLOT:
14141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
14151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
14161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO JMP_SLOT %08x <- %08x %s\n", pid,
14171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
14181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) = sym_addr;
14191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
14201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_GLOB_DAT:
14211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
14221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
14231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO GLOB_DAT %08x <- %08x %s\n", pid,
14241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
14251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) = sym_addr;
14261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
14271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif /* ANDROID_*_LINKER */
14281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if defined(ANDROID_ARM_LINKER)
14301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_RELATIVE:
14311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#elif defined(ANDROID_X86_LINKER)
14321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_RELATIVE:
14331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif /* ANDROID_*_LINKER */
14341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_RELATIVE);
14351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
14361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(sym){
1437d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling                DL_ERR("%5d odd RELATIVE form...", pid);
14381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return -1;
14391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
14401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO RELATIVE %08x <- +%08x\n", pid,
14411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, si->base);
14421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) += si->base;
14431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
14441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if defined(ANDROID_X86_LINKER)
14461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_32:
14471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_RELATIVE);
14481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
14491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO R_386_32 %08x <- +%08x %s\n", pid,
14511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
14521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned *)reloc) += (unsigned)sym_addr;
14531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
14541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_PC32:
14561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_RELATIVE);
14571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
14581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO R_386_PC32 %08x <- "
14591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       "+%08x (%08x - %08x) %s\n", pid, reloc,
14601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       (sym_addr - reloc), sym_addr, reloc, sym_name);
14611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned *)reloc) += (unsigned)(sym_addr - reloc);
14621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
14631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif /* ANDROID_X86_LINKER */
14641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifdef ANDROID_ARM_LINKER
14661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_COPY:
14671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_COPY);
14681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
14691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO %08x <- %d @ %08x %s\n", pid,
14701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, s->st_size, sym_addr, sym_name);
14711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            memcpy((void*)reloc, (void*)sym_addr, s->st_size);
14721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
14735e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev        case R_ARM_NONE:
14745e12d7ec70472659623d2e4552a670d8877f2423Iliyan Malchev            break;
14751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif /* ANDROID_ARM_LINKER */
14761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        default:
1478d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling            DL_ERR("%5d unknown reloc type %d @ %p (%d)",
14791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, type, rel, (int) (rel - start));
14801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return -1;
14811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
14821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        rel++;
14831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
14841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
14851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
14861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1487ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI#if defined(ANDROID_SH_LINKER)
1488ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKIstatic int reloc_library_a(soinfo *si, Elf32_Rela *rela, unsigned count)
1489ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI{
1490ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI    Elf32_Sym *symtab = si->symtab;
1491ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI    const char *strtab = si->strtab;
1492ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI    Elf32_Sym *s;
1493ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI    unsigned base;
1494ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI    Elf32_Rela *start = rela;
1495ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI    unsigned idx;
1496ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI
1497ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI    for (idx = 0; idx < count; ++idx) {
1498ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        unsigned type = ELF32_R_TYPE(rela->r_info);
1499ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        unsigned sym = ELF32_R_SYM(rela->r_info);
1500ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        unsigned reloc = (unsigned)(rela->r_offset + si->base);
1501ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        unsigned sym_addr = 0;
1502ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        char *sym_name = NULL;
1503ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI
1504ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        DEBUG("%5d Processing '%s' relocation at index %d\n", pid,
1505ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI              si->name, idx);
1506ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        if(sym != 0) {
1507ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            sym_name = (char *)(strtab + symtab[sym].st_name);
1508ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            s = _do_lookup(si, sym_name, &base);
1509ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            if(s == 0) {
1510ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI                DL_ERR("%5d cannot locate '%s'...", pid, sym_name);
1511ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI                return -1;
1512ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            }
1513ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI#if 0
1514ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            if((base == 0) && (si->base != 0)){
1515ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI                    /* linking from libraries to main image is bad */
1516ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI                DL_ERR("%5d cannot locate '%s'...",
1517ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI                       pid, strtab + symtab[sym].st_name);
1518ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI                return -1;
1519ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            }
1520ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI#endif
1521ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            if ((s->st_shndx == SHN_UNDEF) && (s->st_value != 0)) {
1522ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI                DL_ERR("%5d In '%s', shndx=%d && value=0x%08x. We do not "
1523ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI                      "handle this yet", pid, si->name, s->st_shndx,
1524ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI                      s->st_value);
1525ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI                return -1;
1526ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            }
1527ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            sym_addr = (unsigned)(s->st_value + base);
1528ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            COUNT_RELOC(RELOC_SYMBOL);
1529ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        } else {
1530ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            s = 0;
1531ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        }
1532ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI
1533ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI/* TODO: This is ugly. Split up the relocations by arch into
1534ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI * different files.
1535ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI */
1536ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        switch(type){
1537ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        case R_SH_JUMP_SLOT:
1538ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            COUNT_RELOC(RELOC_ABSOLUTE);
1539ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            MARK(rela->r_offset);
1540ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            TRACE_TYPE(RELO, "%5d RELO JMP_SLOT %08x <- %08x %s\n", pid,
1541ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI                       reloc, sym_addr, sym_name);
1542ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            *((unsigned*)reloc) = sym_addr;
1543ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            break;
1544ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        case R_SH_GLOB_DAT:
1545ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            COUNT_RELOC(RELOC_ABSOLUTE);
1546ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            MARK(rela->r_offset);
1547ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            TRACE_TYPE(RELO, "%5d RELO GLOB_DAT %08x <- %08x %s\n", pid,
1548ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI                       reloc, sym_addr, sym_name);
1549ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            *((unsigned*)reloc) = sym_addr;
1550ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            break;
1551ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        case R_SH_DIR32:
1552ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            COUNT_RELOC(RELOC_ABSOLUTE);
1553ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            MARK(rela->r_offset);
1554ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            TRACE_TYPE(RELO, "%5d RELO DIR32 %08x <- %08x %s\n", pid,
1555ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI                       reloc, sym_addr, sym_name);
1556ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            *((unsigned*)reloc) += sym_addr;
1557ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            break;
1558ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        case R_SH_RELATIVE:
1559ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            COUNT_RELOC(RELOC_RELATIVE);
1560ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            MARK(rela->r_offset);
1561ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            if(sym){
1562ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI                DL_ERR("%5d odd RELATIVE form...", pid);
1563ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI                return -1;
1564ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            }
1565ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            TRACE_TYPE(RELO, "%5d RELO RELATIVE %08x <- +%08x\n", pid,
1566ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI                       reloc, si->base);
1567ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            *((unsigned*)reloc) += si->base;
1568ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            break;
1569ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI
1570ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        default:
1571ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            DL_ERR("%5d unknown reloc type %d @ %p (%d)",
1572ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI                  pid, type, rela, (int) (rela - start));
1573ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            return -1;
1574ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        }
1575ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        rela++;
1576ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI    }
1577ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI    return 0;
1578ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI}
1579ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI#endif /* ANDROID_SH_LINKER */
1580ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI
15818215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
15828215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner/* Please read the "Initialization and Termination functions" functions.
15838215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner * of the linker design note in bionic/linker/README.TXT to understand
15848215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner * what the following code is doing.
15858215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *
15868215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner * The important things to remember are:
15878215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *
15888215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *   DT_PREINIT_ARRAY must be called first for executables, and should
15898215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *   not appear in shared libraries.
15908215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *
15918215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *   DT_INIT should be called before DT_INIT_ARRAY if both are present
15928215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *
15938215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *   DT_FINI should be called after DT_FINI_ARRAY if both are present
15948215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *
15958215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner *   DT_FINI_ARRAY must be parsed in reverse order.
15968215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner */
15978215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
15988215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turnerstatic void call_array(unsigned *ctor, int count, int reverse)
15991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
16008215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner    int n, inc = 1;
16018215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
16028215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner    if (reverse) {
16038215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        ctor += (count-1);
16048215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        inc   = -1;
16058215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner    }
16068215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
16078215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner    for(n = count; n > 0; n--) {
16088215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        TRACE("[ %5d Looking at %s *0x%08x == 0x%08x ]\n", pid,
16098215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner              reverse ? "dtor" : "ctor",
16101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)ctor, (unsigned)*ctor);
16118215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        void (*func)() = (void (*)()) *ctor;
16128215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        ctor += inc;
16131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(((int) func == 0) || ((int) func == -1)) continue;
16141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling func @ 0x%08x ]\n", pid, (unsigned)func);
16151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        func();
16161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
16181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void call_constructors(soinfo *si)
16201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
16211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->flags & FLAG_EXE) {
16221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling preinit_array @ 0x%08x [%d] for '%s' ]\n",
16231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, (unsigned)si->preinit_array, si->preinit_array_count,
16241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              si->name);
16258215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        call_array(si->preinit_array, si->preinit_array_count, 0);
16261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling preinit_array for '%s' ]\n", pid, si->name);
16271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    } else {
16281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (si->preinit_array) {
16292e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin            DL_ERR("%5d Shared library '%s' has a preinit_array table @ 0x%08x."
1630d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling                   " This is INVALID.", pid, si->name,
16312e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                   (unsigned)si->preinit_array);
16321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
16331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->init_func) {
16361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling init_func @ 0x%08x for '%s' ]\n", pid,
16371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)si->init_func, si->name);
16381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->init_func();
16391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling init_func for '%s' ]\n", pid, si->name);
16401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->init_array) {
16431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling init_array @ 0x%08x [%d] for '%s' ]\n", pid,
16441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)si->init_array, si->init_array_count, si->name);
16458215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        call_array(si->init_array, si->init_array_count, 0);
16461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling init_array for '%s' ]\n", pid, si->name);
16471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
16491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16508215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner
16511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void call_destructors(soinfo *si)
16521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
16531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->fini_array) {
16541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling fini_array @ 0x%08x [%d] for '%s' ]\n", pid,
16551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)si->fini_array, si->fini_array_count, si->name);
16568215679b355efe3829bab571bd566dc818ea4cccDavid 'Digit' Turner        call_array(si->fini_array, si->fini_array_count, 1);
16571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling fini_array for '%s' ]\n", pid, si->name);
16581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->fini_func) {
16611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling fini_func @ 0x%08x for '%s' ]\n", pid,
16621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)si->fini_func, si->name);
16631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->fini_func();
16641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling fini_func for '%s' ]\n", pid, si->name);
16651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
16671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* Force any of the closed stdin, stdout and stderr to be associated with
16691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project   /dev/null. */
16701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int nullify_closed_stdio (void)
16711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
16721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int dev_null, i, status;
16731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int return_value = 0;
16741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    dev_null = open("/dev/null", O_RDWR);
16761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (dev_null < 0) {
1677d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("Cannot open /dev/null.");
16781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return -1;
16791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d Opened /dev/null file-descriptor=%d]\n", pid, dev_null);
16811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* If any of the stdio file descriptors is valid and not associated
16831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       with /dev/null, dup /dev/null to it.  */
16841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (i = 0; i < 3; i++) {
16851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* If it is /dev/null already, we are done. */
16861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (i == dev_null)
16871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            continue;
16881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Nullifying stdio file descriptor %d]\n", pid, i);
16901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* The man page of fcntl does not say that fcntl(..,F_GETFL)
16911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           can be interrupted but we do this just to be safe. */
16921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        do {
16931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          status = fcntl(i, F_GETFL);
16941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } while (status < 0 && errno == EINTR);
16951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* If file is openned, we are good. */
16971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (status >= 0)
16981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          continue;
16991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* The only error we allow is that the file descriptor does not
17011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           exist, in which case we dup /dev/null to it. */
17021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (errno != EBADF) {
1703d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling            DL_ERR("nullify_stdio: unhandled error %s", strerror(errno));
17041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return_value = -1;
17051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            continue;
17061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
17071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* Try dupping /dev/null to this stdio file descriptor and
17091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           repeat if there is a signal.  Note that any errors in closing
17101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           the stdio descriptor are lost.  */
17111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        do {
17121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            status = dup2(dev_null, i);
17131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } while (status < 0 && errno == EINTR);
17142e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin
17151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (status < 0) {
1716d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling            DL_ERR("nullify_stdio: dup2 error %s", strerror(errno));
17171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return_value = -1;
17181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            continue;
17191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
17201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
17211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* If /dev/null is not one of the stdio file descriptors, close it. */
17231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (dev_null > 2) {
17241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Closing /dev/null file-descriptor=%d]\n", pid, dev_null);
17252e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        do {
17261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            status = close(dev_null);
17271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } while (status < 0 && errno == EINTR);
17281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (status < 0) {
1730d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling            DL_ERR("nullify_stdio: close error %s", strerror(errno));
17311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return_value = -1;
17321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
17331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
17341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return return_value;
17361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
17371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int link_image(soinfo *si, unsigned wr_offset)
17391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
17401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned *d;
17411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Phdr *phdr = si->phdr;
17421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int phnum = si->phnum;
17431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    INFO("[ %5d linking %s ]\n", pid, si->name);
17451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("%5d si->base = 0x%08x si->flags = 0x%08x\n", pid,
17461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          si->base, si->flags);
17471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->flags & FLAG_EXE) {
17491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* Locate the needed program segments (DYNAMIC/ARM_EXIDX) for
17501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * linkage info if this is the executable. If this was a
17511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * dynamic lib, that would have been done at load time.
17521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         *
17531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * TODO: It's unfortunate that small pieces of this are
17541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * repeated from the load_library routine. Refactor this just
17551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * slightly to reuse these bits.
17561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         */
17571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->size = 0;
17581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for(; phnum > 0; --phnum, ++phdr) {
17591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifdef ANDROID_ARM_LINKER
17601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(phdr->p_type == PT_ARM_EXIDX) {
17611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* exidx entries (used for stack unwinding) are 8 bytes each.
17621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 */
17631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->ARM_exidx = (unsigned *)phdr->p_vaddr;
17641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->ARM_exidx_count = phdr->p_memsz / 8;
17651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
17661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
17671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (phdr->p_type == PT_LOAD) {
17681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* For the executable, we use the si->size field only in
17691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   dl_unwind_find_exidx(), so the meaning of si->size
17701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   is not the size of the executable; it is the last
17711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   virtual address of the loadable part of the executable;
17721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   since si->base == 0 for an executable, we use the
17731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   range [0, si->size) to determine whether a PC value
17741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   falls within the executable section.  Of course, if
17751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   a value is below phdr->p_vaddr, it's not in the
17761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   executable section, but a) we shouldn't be asking for
17771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   such a value anyway, and b) if we have to provide
17781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   an EXIDX for such a value, then the executable's
17791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   EXIDX is probably the better choice.
17801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                */
17811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                DEBUG_DUMP_PHDR(phdr, "PT_LOAD", pid);
17821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (phdr->p_vaddr + phdr->p_memsz > si->size)
17831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    si->size = phdr->p_vaddr + phdr->p_memsz;
17841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* try to remember what range of addresses should be write
17851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * protected */
17861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (!(phdr->p_flags & PF_W)) {
17871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    unsigned _end;
17881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    if (phdr->p_vaddr < si->wrprotect_start)
17901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                        si->wrprotect_start = phdr->p_vaddr;
17911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    _end = (((phdr->p_vaddr + phdr->p_memsz + PAGE_SIZE - 1) &
17921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                             (~PAGE_MASK)));
17931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    if (_end > si->wrprotect_end)
17941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                        si->wrprotect_end = _end;
17951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                }
17961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            } else if (phdr->p_type == PT_DYNAMIC) {
17971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (si->dynamic != (unsigned *)-1) {
17982e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin                    DL_ERR("%5d multiple PT_DYNAMIC segments found in '%s'. "
1799d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling                          "Segment at 0x%08x, previously one found at 0x%08x",
18001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                          pid, si->name, si->base + phdr->p_vaddr,
18011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                          (unsigned)si->dynamic);
18021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    goto fail;
18031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                }
18041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                DEBUG_DUMP_PHDR(phdr, "PT_DYNAMIC", pid);
18051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->dynamic = (unsigned *) (si->base + phdr->p_vaddr);
18061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
18071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
18081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
18091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->dynamic == (unsigned *)-1) {
1811d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("%5d missing PT_DYNAMIC?!", pid);
18121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
18131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
18141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("%5d dynamic = %p\n", pid, si->dynamic);
18161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* extract useful information from dynamic section */
18181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(d = si->dynamic; *d; d++){
18191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        DEBUG("%5d d = %p, d[0] = 0x%08x d[1] = 0x%08x\n", pid, d, d[0], d[1]);
18201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        switch(*d++){
18211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_HASH:
18221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->nbucket = ((unsigned *) (si->base + *d))[0];
18231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->nchain = ((unsigned *) (si->base + *d))[1];
18241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->bucket = (unsigned *) (si->base + *d + 8);
18251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->chain = (unsigned *) (si->base + *d + 8 + si->nbucket * 4);
18261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
18271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_STRTAB:
18281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->strtab = (const char *) (si->base + *d);
18291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
18301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_SYMTAB:
18311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->symtab = (Elf32_Sym *) (si->base + *d);
18321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
1833ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI#if !defined(ANDROID_SH_LINKER)
18341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PLTREL:
18351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(*d != DT_REL) {
1836d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling                DL_ERR("DT_RELA not supported");
18371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                goto fail;
18381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
18391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
1840ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI#endif
1841ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI#ifdef ANDROID_SH_LINKER
1842ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        case DT_JMPREL:
1843ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            si->plt_rela = (Elf32_Rela*) (si->base + *d);
1844ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            break;
1845ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        case DT_PLTRELSZ:
1846ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            si->plt_rela_count = *d / sizeof(Elf32_Rela);
1847ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            break;
1848ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI#else
18491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_JMPREL:
18501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->plt_rel = (Elf32_Rel*) (si->base + *d);
18511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
18521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PLTRELSZ:
18531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->plt_rel_count = *d / 8;
18541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
1855ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI#endif
18561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_REL:
18571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->rel = (Elf32_Rel*) (si->base + *d);
18581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
18591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_RELSZ:
18601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->rel_count = *d / 8;
18611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
1862ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI#ifdef ANDROID_SH_LINKER
1863ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        case DT_RELASZ:
1864ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            si->rela_count = *d / sizeof(Elf32_Rela);
1865ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI             break;
1866ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI#endif
18671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PLTGOT:
18681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* Save this in case we decide to do lazy binding. We don't yet. */
18691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->plt_got = (unsigned *)(si->base + *d);
18701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
18711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_DEBUG:
18721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            // Set the DT_DEBUG entry to the addres of _r_debug for GDB
18731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *d = (int) &_r_debug;
18741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
1875ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI#ifdef ANDROID_SH_LINKER
18761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_RELA:
1877ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            si->rela = (Elf32_Rela *) (si->base + *d);
1878ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            break;
1879ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI#else
1880ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI         case DT_RELA:
1881d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling            DL_ERR("%5d DT_RELA not supported", pid);
18821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            goto fail;
1883ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI#endif
18841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_INIT:
18851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->init_func = (void (*)(void))(si->base + *d);
18861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s constructors (init func) found at %p\n",
18871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->init_func);
18881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
18891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_FINI:
18901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->fini_func = (void (*)(void))(si->base + *d);
18911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s destructors (fini func) found at %p\n",
18921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->fini_func);
18931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
18941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_INIT_ARRAY:
18951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->init_array = (unsigned *)(si->base + *d);
18961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s constructors (init_array) found at %p\n",
18971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->init_array);
18981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
18991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_INIT_ARRAYSZ:
19001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->init_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
19011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
19021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_FINI_ARRAY:
19031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->fini_array = (unsigned *)(si->base + *d);
19041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s destructors (fini_array) found at %p\n",
19051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->fini_array);
19061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
19071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_FINI_ARRAYSZ:
19081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->fini_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
19091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
19101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PREINIT_ARRAY:
19111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->preinit_array = (unsigned *)(si->base + *d);
19121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s constructors (preinit_array) found at %p\n",
19131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->preinit_array);
19141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
19151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PREINIT_ARRAYSZ:
19161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->preinit_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
19171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
19181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_TEXTREL:
19191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* TODO: make use of this. */
19201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* this means that we might have to write into where the text
19211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * segment was loaded during relocation... Do something with
19221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * it.
19231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             */
19241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d Text segment should be writable during relocation.\n",
19251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid);
19261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
19271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
19281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
19291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
19301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("%5d si->base = 0x%08x, si->strtab = %p, si->symtab = %p\n",
19311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           pid, si->base, si->strtab, si->symtab);
19321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
19331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if((si->strtab == 0) || (si->symtab == 0)) {
1934d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling        DL_ERR("%5d missing essential tables", pid);
19351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
19361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
19371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
19384fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    /* if this is the main executable, then load all of the preloads now */
19394fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    if(si->flags & FLAG_EXE) {
19404fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer        int i;
19414fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer        memset(preloads, 0, sizeof(preloads));
19424fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer        for(i = 0; ldpreload_names[i] != NULL; i++) {
19434fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer            soinfo *lsi = find_library(ldpreload_names[i]);
19444fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer            if(lsi == 0) {
19454fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer                strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf));
19464fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer                DL_ERR("%5d could not load needed library '%s' for '%s' (%s)",
19474fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer                       pid, ldpreload_names[i], si->name, tmp_err_buf);
19484fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer                goto fail;
19494fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer            }
19504fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer            lsi->refcount++;
19514fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer            preloads[i] = lsi;
19524fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer        }
19534fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    }
19544fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
19551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(d = si->dynamic; *d; d += 2) {
19561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(d[0] == DT_NEEDED){
19571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s needs %s\n", pid, si->name, si->strtab + d[1]);
19582e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin            soinfo *lsi = find_library(si->strtab + d[1]);
19591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(lsi == 0) {
19600353195f344666256dba474a15c9ba22cf0cccc9Dima Zavin                strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf));
1961d00d23a9d4598108d7f498291b35c7730e48cf5cErik Gilling                DL_ERR("%5d could not load needed library '%s' for '%s' (%s)",
19620353195f344666256dba474a15c9ba22cf0cccc9Dima Zavin                       pid, si->strtab + d[1], si->name, tmp_err_buf);
19631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                goto fail;
19641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
19656ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev            /* Save the soinfo of the loaded DT_NEEDED library in the payload
19666ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev               of the DT_NEEDED entry itself, so that we can retrieve the
19676ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev               soinfo directly later from the dynamic segment.  This is a hack,
19686ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev               but it allows us to map from DT_NEEDED to soinfo efficiently
19696ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev               later on when we resolve relocations, trying to look up a symgol
19706ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev               with dlsym().
19716ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev            */
19726ed80c8814db9eed1fb687be22322e38dc46a2fbIliyan Malchev            d[1] = (unsigned)lsi;
19731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            lsi->refcount++;
19741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
19751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
19761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
19771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si->plt_rel) {
19781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        DEBUG("[ %5d relocating %s plt ]\n", pid, si->name );
19791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(reloc_library(si, si->plt_rel, si->plt_rel_count))
19801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            goto fail;
19811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
19821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si->rel) {
19831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        DEBUG("[ %5d relocating %s ]\n", pid, si->name );
19841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(reloc_library(si, si->rel, si->rel_count))
19851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            goto fail;
19861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
19871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1988ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI#ifdef ANDROID_SH_LINKER
1989ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI    if(si->plt_rela) {
1990ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        DEBUG("[ %5d relocating %s plt ]\n", pid, si->name );
1991ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        if(reloc_library_a(si, si->plt_rela, si->plt_rela_count))
1992ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            goto fail;
1993ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI    }
1994ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI    if(si->rela) {
1995ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        DEBUG("[ %5d relocating %s ]\n", pid, si->name );
1996ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI        if(reloc_library_a(si, si->rela, si->rela_count))
1997ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI            goto fail;
1998ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI    }
1999ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI#endif /* ANDROID_SH_LINKER */
2000ad13c57298e57d33c130fb03a2c6494da573408cShin-ichiro KAWASAKI
20011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags |= FLAG_LINKED;
20021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("[ %5d finished linking %s ]\n", pid, si->name);
20031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
20041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
20051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* This is the way that the old dynamic linker did protection of
20061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * non-writable areas. It would scan section headers and find where
20071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * .text ended (rather where .data/.bss began) and assume that this is
20081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * the upper range of the non-writable area. This is too coarse,
20091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * and is kept here for reference until we fully move away from single
20101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * segment elf objects. See the code in get_wr_offset (also #if'd 0)
20111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * that made this possible.
20121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
20131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(wr_offset < 0xffffffff){
20141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        mprotect((void*) si->base, wr_offset, PROT_READ | PROT_EXEC);
20151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
20161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#else
20171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* TODO: Verify that this does the right thing in all cases, as it
20181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * presently probably does not. It is possible that an ELF image will
20191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * come with multiple read-only segments. What we ought to do is scan
20201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * the program headers again and mprotect all the read-only segments.
20211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * To prevent re-scanning the program header, we would have to build a
20221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * list of loadable segments in si, and then scan that instead. */
20231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->wrprotect_start != 0xffffffff && si->wrprotect_end != 0) {
20241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        mprotect((void *)si->wrprotect_start,
20251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 si->wrprotect_end - si->wrprotect_start,
20261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 PROT_READ | PROT_EXEC);
20271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
20281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
20291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
20301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* If this is a SET?ID program, dup /dev/null to opened stdin,
20311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       stdout and stderr to close a security hole described in:
20321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
20331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc
20341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
20351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
20361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (getuid() != geteuid() || getgid() != getegid())
20371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        nullify_closed_stdio ();
20381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    call_constructors(si);
20391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    notify_gdb_of_load(si);
20401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
20411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
20421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectfail:
2043a716190241da07f42cf874b04bf044261f36381cDima Zavin    ERROR("failed to link %s\n", si->name);
20441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags |= FLAG_ERROR;
20451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
20461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
20471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2048bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartleystatic void parse_library_path(char *path, char *delim)
2049bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley{
2050bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    size_t len;
2051bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    char *ldpaths_bufp = ldpaths_buf;
2052bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    int i = 0;
2053bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
2054bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    len = strlcpy(ldpaths_buf, path, sizeof(ldpaths_buf));
2055bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
2056bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    while (i < LDPATH_MAX && (ldpaths[i] = strsep(&ldpaths_bufp, delim))) {
2057bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        if (*ldpaths[i] != '\0')
2058bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            ++i;
2059bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    }
2060bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
2061bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    /* Forget the last path if we had to truncate; this occurs if the 2nd to
2062bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley     * last char isn't '\0' (i.e. not originally a delim). */
2063bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    if (i > 0 && len >= sizeof(ldpaths_buf) &&
2064bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            ldpaths_buf[sizeof(ldpaths_buf) - 2] != '\0') {
2065bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        ldpaths[i - 1] = NULL;
2066bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    } else {
2067bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        ldpaths[i] = NULL;
2068bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    }
2069bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley}
2070bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
20714fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischerstatic void parse_preloads(char *path, char *delim)
20724fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer{
20734fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    size_t len;
20744fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    char *ldpreloads_bufp = ldpreloads_buf;
20754fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    int i = 0;
20764fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
20774fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    len = strlcpy(ldpreloads_buf, path, sizeof(ldpreloads_buf));
20784fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
20794fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    while (i < LDPRELOAD_MAX && (ldpreload_names[i] = strsep(&ldpreloads_bufp, delim))) {
20804fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer        if (*ldpreload_names[i] != '\0') {
20814fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer            ++i;
20824fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer        }
20834fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    }
20844fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
20854fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    /* Forget the last path if we had to truncate; this occurs if the 2nd to
20864fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer     * last char isn't '\0' (i.e. not originally a delim). */
20874fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    if (i > 0 && len >= sizeof(ldpreloads_buf) &&
20884fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer            ldpreloads_buf[sizeof(ldpreloads_buf) - 2] != '\0') {
20894fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer        ldpreload_names[i - 1] = NULL;
20904fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    } else {
20914fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer        ldpreload_names[i] = NULL;
20924fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    }
20934fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer}
20944fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
20951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint main(int argc, char **argv)
20961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
20971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
20981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
20991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
21001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define ANDROID_TLS_SLOTS  BIONIC_TLS_SLOTS
21011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
21021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void * __tls_area[ANDROID_TLS_SLOTS];
21031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
21041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectunsigned __linker_init(unsigned **elfdata)
21051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
21061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    static soinfo linker_soinfo;
21071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
21081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int argc = (int) *elfdata;
21091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    char **argv = (char**) (elfdata + 1);
21101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned *vecs = (unsigned*) (argv + argc + 1);
21111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
21121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct link_map * map;
2113bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    char *ldpath_env = NULL;
21144fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    char *ldpreload_env = NULL;
21151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2116ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner    /* Setup a temporary TLS area that is used to get a working
2117ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner     * errno for system calls.
2118ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner     */
2119ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner    __set_tls(__tls_area);
2120ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner
21211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    pid = getpid();
21221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
21231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING
21241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct timeval t0, t1;
21251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    gettimeofday(&t0, 0);
21261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
21271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2128ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner    /* NOTE: we store the elfdata pointer on a special location
2129ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner     *       of the temporary TLS area in order to pass it to
2130ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner     *       the C Library's runtime initializer.
2131ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner     *
2132ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner     *       The initializer must clear the slot and reset the TLS
2133ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner     *       to point to a different location to ensure that no other
2134ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner     *       shared library constructor can access it.
2135ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner     */
2136ef0bd1857041ffde069cf52138aaf22c1af7130eDavid 'Digit' Turner    __tls_area[TLS_SLOT_BIONIC_PREINIT] = elfdata;
21371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
21381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    debugger_init();
21391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
21401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* skip past the environment */
21411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    while(vecs[0] != 0) {
21421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(!strncmp((char*) vecs[0], "DEBUG=", 6)) {
21431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            debug_verbosity = atoi(((char*) vecs[0]) + 6);
2144bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        } else if(!strncmp((char*) vecs[0], "LD_LIBRARY_PATH=", 16)) {
2145bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley            ldpath_env = (char*) vecs[0] + 16;
21464fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer        } else if(!strncmp((char*) vecs[0], "LD_PRELOAD=", 11)) {
21474fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer            ldpreload_env = (char*) vecs[0] + 11;
21481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
21491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        vecs++;
21501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
21511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    vecs++;
21521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
21531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    INFO("[ android linker & debugger ]\n");
21541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("%5d elfdata @ 0x%08x\n", pid, (unsigned)elfdata);
21551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
21561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si = alloc_info(argv[0]);
21571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si == 0) {
21581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        exit(-1);
21591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
21601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
21611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* bootstrap the link map, the main exe always needs to be first */
21621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags |= FLAG_EXE;
21631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map = &(si->linkmap);
21641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
21651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_addr = 0;
21661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_name = argv[0];
21671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_prev = NULL;
21681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_next = NULL;
21691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
21701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_map = map;
21711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    r_debug_tail = map;
21721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
21731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* gdb expects the linker to be in the debug shared object list,
21741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * and we need to make sure that the reported load address is zero.
21751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * Without this, gdb gets the wrong idea of where rtld_db_dlactivity()
21761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * is.  Don't use alloc_info(), because the linker shouldn't
21771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * be on the soinfo list.
21781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         */
21791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    strcpy((char*) linker_soinfo.name, "/system/bin/linker");
21801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    linker_soinfo.flags = 0;
21811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    linker_soinfo.base = 0;     // This is the important part; must be zero.
21821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    insert_soinfo_into_debug_map(&linker_soinfo);
21831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
21841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* extract information passed from the kernel */
21851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    while(vecs[0] != 0){
21861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        switch(vecs[0]){
21871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case AT_PHDR:
21881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->phdr = (Elf32_Phdr*) vecs[1];
21891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
21901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case AT_PHNUM:
21911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->phnum = (int) vecs[1];
21921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
21931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case AT_ENTRY:
21941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->entry = vecs[1];
21951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
21961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
21971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        vecs += 2;
21981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
21991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2200e100f52f4ad1b70762bbcc5ad9828bd258917ee5Iliyan Malchev    ba_init(&ba_nonprelink);
22011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
22021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->base = 0;
22031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->dynamic = (unsigned *)-1;
22041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->wrprotect_start = 0xffffffff;
22051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->wrprotect_end = 0;
22066774809b6249d9d4efd982b6e3ca377c84482d9aDavid 'Digit' Turner    si->refcount = 1;
22071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2208bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        /* Use LD_LIBRARY_PATH if we aren't setuid/setgid */
2209bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley    if (ldpath_env && getuid() == geteuid() && getgid() == getegid())
2210bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley        parse_library_path(ldpath_env, ":");
2211bc3a5c26f1b9cf29da6abfc3e197258ef4c03362David Bartley
22124fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    if (ldpreload_env && getuid() == geteuid() && getgid() == getegid()) {
22134fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer        parse_preloads(ldpreload_env, " :");
22144fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer    }
22154fd42c1dc002fa19349fa0d4ef97757eb1815032Matt Fischer
22162e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin    if(link_image(si, 0)) {
22172e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        char errmsg[] = "CANNOT LINK EXECUTABLE\n";
22182e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf));
22192e85579c34047c305caf15fb0ebe02bf3d001d0eDima Zavin        write(2, errmsg, sizeof(errmsg));
22201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        exit(-1);
22211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
22221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
22234a9afcb10151b083cd2d75253385615f459172edIliyan Malchev#if ALLOW_SYMBOLS_FROM_MAIN
22244a9afcb10151b083cd2d75253385615f459172edIliyan Malchev    /* Set somain after we've loaded all the libraries in order to prevent
22254a9afcb10151b083cd2d75253385615f459172edIliyan Malchev     * linking of symbols back to the main image, which is not set up at that
22264a9afcb10151b083cd2d75253385615f459172edIliyan Malchev     * point yet.
22274a9afcb10151b083cd2d75253385615f459172edIliyan Malchev     */
22284a9afcb10151b083cd2d75253385615f459172edIliyan Malchev    somain = si;
22294a9afcb10151b083cd2d75253385615f459172edIliyan Malchev#endif
22304a9afcb10151b083cd2d75253385615f459172edIliyan Malchev
22311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING
22321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    gettimeofday(&t1,NULL);
22331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    PRINT("LINKER TIME: %s: %d microseconds\n", argv[0], (int) (
22341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
22351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)
22361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               ));
22371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
22381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS
22391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol\n", argv[0],
22401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           linker_stats.reloc[RELOC_ABSOLUTE],
22411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           linker_stats.reloc[RELOC_RELATIVE],
22421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           linker_stats.reloc[RELOC_COPY],
22431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           linker_stats.reloc[RELOC_SYMBOL]);
22441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
22451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES
22461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    {
22471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned n;
22481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned i;
22491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned count = 0;
22501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for(n = 0; n < 4096; n++){
22511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(bitmask[n]){
22521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                unsigned x = bitmask[n];
22531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                for(i = 0; i < 8; i++){
22541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    if(x & 1) count++;
22551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    x >>= 1;
22561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                }
22571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
22581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
22591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        PRINT("PAGES MODIFIED: %s: %d (%dKB)\n", argv[0], count, count * 4);
22601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
22611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
22621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
22631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING || STATS || COUNT_PAGES
22641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    fflush(stdout);
22651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
22661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
22671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d Ready to execute '%s' @ 0x%08x ]\n", pid, si->name,
22681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          si->entry);
22691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si->entry;
22701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2271