linker.cpp revision 1dc9e472e19acfe6dc7f41e429236e7eef7ceda1
11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright (C) 2008 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
401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project//#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"
511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "ba.h"
531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define SO_MAX 64
551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<<
571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Do NOT use malloc() and friends or pthread_*() code here.
591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Don't use printf() either; it's caused mysterious memory
601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * corruption in the past.
611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * The linker runs before we bring up libc and it's easiest
621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * to make sure it does not depend on any complex libc features
631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * open issues / todo:
651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - should we do anything special for STB_WEAK symbols?
671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - are we doing everything we should for ARM_COPY relocations?
681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - cleaner error reporting
691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - configuration for paths (LD_LIBRARY_PATH?)
701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - after linking, set as much stuff as possible to READONLY
711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   and NOEXEC
721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - linker hardcodes PAGE_SIZE and PAGE_MASK because the kernel
731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   headers provide versions that are negative...
741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - allocate space for soinfo structs dynamically instead of
751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   having a hard limit (64)
761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * features to add someday:
781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * - dlopen() and friends
801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project*/
821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int link_image(soinfo *si, unsigned wr_offset);
851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int socount = 0;
871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo sopool[SO_MAX];
881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *freelist = NULL;
891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *solist = &libdl_info;
901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *sonext = &libdl_info;
911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint debug_verbosity;
931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int pid;
941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS
961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstruct _link_stats linker_stats;
971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES
1001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectunsigned bitmask[4096];
1011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifndef PT_ARM_EXIDX
1041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define PT_ARM_EXIDX    0x70000001      /* .ARM.exidx segment */
1051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
1061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
1081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * This function is an empty stub where GDB locates a breakpoint to get notified
1091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * about linker activity.
1101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
1111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectextern void __attribute__((noinline)) rtld_db_dlactivity(void);
1121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectextern void  sched_yield(void);
1141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic struct r_debug _r_debug = {1, NULL, &rtld_db_dlactivity,
1161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                  RT_CONSISTENT, 0};
1171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic struct link_map *r_debug_tail = 0;
1181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project//static pthread_mutex_t _r_debug_lock = PTHREAD_MUTEX_INITIALIZER;
1201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic volatile int loader_lock = 0;
1221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void insert_soinfo_into_debug_map(soinfo * info)
1241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
1251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct link_map * map;
1261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Copy the necessary fields into the debug structure.
1281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
1291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map = &(info->linkmap);
1301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_addr = info->base;
1311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_name = (char*) info->name;
1321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Stick the new library at the end of the list.
1341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * gdb tends to care more about libc than it does
1351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * about leaf libraries, and ordering it this way
1361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * reduces the back-and-forth over the wire.
1371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
1381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (r_debug_tail) {
1391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        r_debug_tail->l_next = map;
1401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        map->l_prev = r_debug_tail;
1411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        map->l_next = 0;
1421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    } else {
1431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        _r_debug.r_map = map;
1441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        map->l_prev = 0;
1451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        map->l_next = 0;
1461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
1471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    r_debug_tail = map;
1481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
1491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid notify_gdb_of_load(soinfo * info)
1511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
1521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (info->flags & FLAG_EXE) {
1531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        // GDB already knows about the main executable
1541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return;
1551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
1561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* yes, this is a little gross, but it does avoid
1581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        ** pulling in pthread_*() and at the moment we don't
1591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        ** dlopen() anything anyway
1601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        */
1611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    while(__atomic_swap(1, &loader_lock) != 0) {
1621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        sched_yield();
1631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        usleep(5000);
1641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
1651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_state = RT_ADD;
1671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    rtld_db_dlactivity();
1681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    insert_soinfo_into_debug_map(info);
1701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_state = RT_CONSISTENT;
1721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    rtld_db_dlactivity();
1731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    __atomic_swap(0, &loader_lock);
1751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
1761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid notify_gdb_of_libraries()
1781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
1791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_state = RT_ADD;
1801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    rtld_db_dlactivity();
1811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_state = RT_CONSISTENT;
1821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    rtld_db_dlactivity();
1831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
1841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *alloc_info(const char *name)
1861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
1871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
1881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(strlen(name) >= SOINFO_NAME_LEN) {
1901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        ERROR("%5d library name %s too long\n", pid, name);
1911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return 0;
1921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
1931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* The freelist is populated when we call free_info(), which in turn is
1951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       done only by dlclose(), which is not likely to be used.
1961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    */
1971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (!freelist) {
1981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(socount == SO_MAX) {
1991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ERROR("%5d too many libraries when loading %s\n", pid, name);
2001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return NULL;
2011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
2021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        freelist = sopool + socount++;
2031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        freelist->next = NULL;
2041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si = freelist;
2071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    freelist = freelist->next;
2081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Make sure we get a clean block of soinfo */
2101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    memset(si, 0, sizeof(soinfo));
2111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    strcpy((char*) si->name, name);
2121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    sonext->next = si;
2131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->ba_index = -1; /* by default, prelinked */
2141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->next = NULL;
2151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->refcount = 0;
2161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    sonext = si;
2171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("%5d name %s: allocated soinfo @ %p\n", pid, name, si);
2191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si;
2201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void free_info(soinfo *si)
2231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
2241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *prev = NULL, *trav;
2251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("%5d name %s: freeing soinfo @ %p\n", pid, si->name, si);
2271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(trav = solist; trav != NULL; trav = trav->next){
2291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (trav == si)
2301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
2311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        prev = trav;
2321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (trav == NULL) {
2341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* si was not ni solist */
2351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        ERROR("%5d name %s is not in solist!\n", pid, si->name);
2361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return;
2371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* prev will never be NULL, because the first entry in solist is
2401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       always the static libdl_info.
2411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    */
2421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    prev->next = si->next;
2431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si == sonext) sonext = prev;
2441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->next = freelist;
2451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    freelist = si;
2461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifndef LINKER_TEXT_BASE
2491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#error "linker's makefile must define LINKER_TEXT_BASE"
2501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
2511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifndef LINKER_AREA_SIZE
2521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#error "linker's makefile must define LINKER_AREA_SIZE"
2531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
2541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define LINKER_BASE ((LINKER_TEXT_BASE) & 0xfff00000)
2551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define LINKER_TOP  (LINKER_BASE + (LINKER_AREA_SIZE))
2561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectconst char *addr_to_name(unsigned addr)
2581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
2591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
2601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(si = solist; si != 0; si = si->next){
2621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if((addr >= si->base) && (addr < (si->base + si->size))) {
2631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return si->name;
2641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
2651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if((addr >= LINKER_BASE) && (addr < LINKER_TOP)){
2681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return "linker";
2691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return "";
2721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* For a given PC, find the .so that it belongs to.
2751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns the base address of the .ARM.exidx section
2761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * for that .so, and the number of 8-byte entries
2771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * in that section (via *pcount).
2781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
2791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Intended to be called by libc's __gnu_Unwind_Find_exidx().
2801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
2811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * This function is exposed via dlfcn.c and libdl.so.
2821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
2831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifdef ANDROID_ARM_LINKER
2841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount)
2851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
2861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
2871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned addr = (unsigned)pc;
2881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((addr < LINKER_BASE) || (addr >= LINKER_TOP)) {
2901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for (si = solist; si != 0; si = si->next){
2911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if ((addr >= si->base) && (addr < (si->base + si->size))) {
2921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                *pcount = si->ARM_exidx_count;
2931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return (_Unwind_Ptr)(si->base + (unsigned long)si->ARM_exidx);
2941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
2951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
2961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project   *pcount = 0;
2981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return NULL;
2991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#elif defined(ANDROID_X86_LINKER)
3011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* Here, we only have to provide a callback to iterate across all the
3021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * loaded libraries. gcc_eh does the rest. */
3031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint
3041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdl_iterate_phdr(int (*cb)(struct dl_phdr_info *info, size_t size, void *data),
3051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                void *data)
3061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
3081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct dl_phdr_info dl_info;
3091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int rv = 0;
3101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (si = solist; si != NULL; si = si->next) {
3121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        dl_info.dlpi_addr = si->linkmap.l_addr;
3131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        dl_info.dlpi_name = si->linkmap.l_name;
3141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        dl_info.dlpi_phdr = si->phdr;
3151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        dl_info.dlpi_phnum = si->phnum;
3161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        rv = cb(&dl_info, sizeof (struct dl_phdr_info), data);
3171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (rv != 0)
3181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
3191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return rv;
3211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
3231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic Elf32_Sym *_elf_lookup(soinfo *si, unsigned hash, const char *name)
3251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *s;
3271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *symtab = si->symtab;
3281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    const char *strtab = si->strtab;
3291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned n;
3301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE_TYPE(LOOKUP, "%5d SEARCH %s in %s@0x%08x %08x %d\n", pid,
3321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               name, si->name, si->base, hash, hash % si->nbucket);
3331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    n = hash % si->nbucket;
3341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]){
3361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        s = symtab + n;
3371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(strcmp(strtab + s->st_name, name)) continue;
3381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* only concern ourselves with global symbols */
3401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        switch(ELF32_ST_BIND(s->st_info)){
3411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case STB_GLOBAL:
3421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* no section == undefined */
3431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(s->st_shndx == 0) continue;
3441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case STB_WEAK:
3461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(LOOKUP, "%5d FOUND %s in %s (%08x) %d\n", pid,
3471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       name, si->name, s->st_value, s->st_size);
3481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return s;
3491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
3501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
3531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned elfhash(const char *_name)
3561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    const unsigned char *name = (const unsigned char *) _name;
3581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned h = 0, g;
3591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    while(*name) {
3611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        h = (h << 4) + *name++;
3621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        g = h & 0xf0000000;
3631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        h ^= g;
3641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        h ^= g >> 24;
3651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return h;
3671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic Elf32_Sym *
3701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project_do_lookup_in_so(soinfo *si, const char *name, unsigned *elf_hash)
3711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (*elf_hash == 0)
3731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        *elf_hash = elfhash(name);
3741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return _elf_lookup (si, *elf_hash, name);
3751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* This is used by dl_sym() */
3781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source ProjectElf32_Sym *lookup_in_library(soinfo *si, const char *name)
3791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned unused = 0;
3811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return _do_lookup_in_so(si, name, &unused);
3821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic Elf32_Sym *
3851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project_do_lookup(soinfo *user_si, const char *name, unsigned *base)
3861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned elf_hash = 0;
3881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *s = NULL;
3891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
3901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Look for symbols in the local scope first (the object who is
3921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * searching). This happens with C++ templates on i386 for some
3931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * reason. */
3941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (user_si) {
3951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        s = _do_lookup_in_so(user_si, name, &elf_hash);
3961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (s != NULL)
3971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *base = user_si->base;
3981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(si = solist; (s == NULL) && (si != NULL); si = si->next)
4011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    {
4021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if((si->flags & FLAG_ERROR) || (si == user_si))
4031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            continue;
4041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        s = _do_lookup_in_so(si, name, &elf_hash);
4051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (s != NULL) {
4061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *base = si->base;
4071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
4081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
4091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
4101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (s != NULL) {
4121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE_TYPE(LOOKUP, "%5d %s s->st_value = 0x%08x, "
4131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   "si->base = 0x%08x\n", pid, name, s->st_value, si->base);
4141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return s;
4151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
4161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
4181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* This is used by dl_sym() */
4211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source ProjectElf32_Sym *lookup(const char *name, unsigned *base)
4221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
4231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return _do_lookup(NULL, name, base);
4241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
4271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void dump(soinfo *si)
4281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
4291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *s = si->symtab;
4301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned n;
4311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(n = 0; n < si->nchain; n++) {
4331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("%5d %04d> %08x: %02x %04x %08x %08x %s\n", pid, n, s,
4341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               s->st_info, s->st_shndx, s->st_value, s->st_size,
4351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               si->strtab + s->st_name);
4361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        s++;
4371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
4381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
4401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic const char *sopaths[] = {
4421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    "/system/lib",
4431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    "/lib",
4441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    0
4451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project};
4461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int _open_lib(const char *name)
4481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
4491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int fd;
4501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct stat filestat;
4511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((stat(name, &filestat) >= 0) && S_ISREG(filestat.st_mode)) {
4531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if ((fd = open(name, O_RDONLY)) >= 0)
4541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return fd;
4551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
4561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
4581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* TODO: Need to add support for initializing the so search path with
4611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * LD_LIBRARY_PATH env variable for non-setuid programs. */
4621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int open_library(const char *name)
4631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
4641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int fd;
4651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    char buf[512];
4661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    const char **path;
4671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d opening %s ]\n", pid, name);
4691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(name == 0) return -1;
4711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(strlen(name) > 256) return -1;
4721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((name[0] == '/') && ((fd = _open_lib(name)) >= 0))
4741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return fd;
4751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (path = sopaths; *path; path++) {
4771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        snprintf(buf, sizeof(buf), "%s/%s", *path, name);
4781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if ((fd = _open_lib(buf)) >= 0)
4791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return fd;
4801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
4811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
4831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
4841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* temporary space for holding the first page of the shared lib
4861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * which contains the elf header (with the pht). */
4871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned char __header[PAGE_SIZE];
4881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecttypedef struct {
4901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    long mmap_addr;
4911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    char tag[4]; /* 'P', 'R', 'E', ' ' */
4921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} prelink_info_t;
4931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* Returns the requested base address if the library is prelinked,
4951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * and 0 otherwise.  */
4961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned long
4971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectis_prelinked(int fd, const char *name)
4981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
4991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    off_t sz;
5001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    prelink_info_t info;
5011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    sz = lseek(fd, -sizeof(prelink_info_t), SEEK_END);
5031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (sz < 0) {
5041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        ERROR("lseek() failed!\n");
5051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return 0;
5061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
5071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (read(fd, &info, sizeof(info)) != sizeof(info)) {
5091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        WARN("Could not read prelink_info_t structure for `%s`\n", name);
5101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return 0;
5111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
5121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (strncmp(info.tag, "PRE ", 4)) {
5141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        WARN("`%s` is not a prelinked library\n", name);
5151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return 0;
5161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
5171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return (unsigned long)info.mmap_addr;
5191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
5201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* verify_elf_object
5221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      Verifies if the object @ base is a valid ELF object
5231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
5241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Args:
5251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
5261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns:
5271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *       0 on success
5281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      -1 if no valid ELF object is found @ base.
5291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
5301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int
5311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectverify_elf_object(void *base, const char *name)
5321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
5331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Ehdr *hdr = (Elf32_Ehdr *) base;
5341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (hdr->e_ident[EI_MAG0] != ELFMAG0) return -1;
5361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (hdr->e_ident[EI_MAG1] != ELFMAG1) return -1;
5371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (hdr->e_ident[EI_MAG2] != ELFMAG2) return -1;
5381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (hdr->e_ident[EI_MAG3] != ELFMAG3) return -1;
5391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* TODO: Should we verify anything else in the header? */
5411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
5431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
5441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* get_lib_extents
5471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      Retrieves the base (*base) address where the ELF object should be
5481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      mapped and its overall memory size (*total_sz).
5491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
5501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Args:
5511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      fd: Opened file descriptor for the library
5521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      name: The name of the library
5531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      _hdr: Pointer to the header page of the library
5541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      total_sz: Total size of the memory that should be allocated for
5551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *                this library
5561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
5571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns:
5581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      -1 if there was an error while trying to get the lib extents.
5591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *         The possible reasons are:
5601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *             - Could not determine if the library was prelinked.
5611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *             - The library provided is not a valid ELF object
5621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *       0 if the library did not request a specific base offset (normal
5631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *         for non-prelinked libs)
5641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     > 0 if the library requests a specific address to be mapped to.
5651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *         This indicates a pre-linked library.
5661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
5671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned
5681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectget_lib_extents(int fd, const char *name, void *__hdr, unsigned *total_sz)
5691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
5701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned req_base;
5711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned min_vaddr = 0xffffffff;
5721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned max_vaddr = 0;
5731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *_hdr = (unsigned char *)__hdr;
5741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Ehdr *ehdr = (Elf32_Ehdr *)_hdr;
5751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Phdr *phdr;
5761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int cnt;
5771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d Computing extents for '%s'. ]\n", pid, name);
5791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (verify_elf_object(_hdr, name) < 0) {
5801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        ERROR("%5d - %s is not a valid ELF object\n", pid, name);
5811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return (unsigned)-1;
5821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
5831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    req_base = (unsigned) is_prelinked(fd, name);
5851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (req_base == (unsigned)-1)
5861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return -1;
5871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    else if (req_base != 0) {
5881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d - Prelinked library '%s' requesting base @ 0x%08x ]\n",
5891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, name, req_base);
5901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    } else {
5911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d - Non-prelinked library '%s' found. ]\n", pid, name);
5921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
5931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    phdr = (Elf32_Phdr *)(_hdr + ehdr->e_phoff);
5951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* find the min/max p_vaddrs from all the PT_LOAD segments so we can
5971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * get the range. */
5981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (cnt = 0; cnt < ehdr->e_phnum; ++cnt, ++phdr) {
5991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (phdr->p_type == PT_LOAD) {
6001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if ((phdr->p_vaddr + phdr->p_memsz) > max_vaddr)
6011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                max_vaddr = phdr->p_vaddr + phdr->p_memsz;
6021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (phdr->p_vaddr < min_vaddr)
6031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                min_vaddr = phdr->p_vaddr;
6041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
6051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((min_vaddr == 0xffffffff) && (max_vaddr == 0)) {
6081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        ERROR("%5d - No loadable segments found in %s.\n", pid, name);
6091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return (unsigned)-1;
6101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* truncate min_vaddr down to page boundary */
6131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    min_vaddr &= ~PAGE_MASK;
6141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* round max_vaddr up to the next page */
6161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    max_vaddr = (max_vaddr + PAGE_SIZE - 1) & ~PAGE_MASK;
6171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    *total_sz = (max_vaddr - min_vaddr);
6191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return (unsigned)req_base;
6201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
6211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* alloc_mem_region
6231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
6241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     This function reserves a chunk of memory to be used for mapping in
6251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     the shared library. We reserve the entire memory region here, and
6261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     then the rest of the linker will relocate the individual loadable
6271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     segments into the correct locations within this memory range.
6281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
6291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Args:
6301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     si->base: The requested base of the allocation. If 0, a sane one will be
6311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *               chosen in the range LIBBASE <= base < LIBLAST.
6321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     si->size: The size of the allocation.
6331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
6341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns:
6351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     -1 on failure, and 0 on success.  On success, si->base will contain
6361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     the virtual address at which the library will be mapped.
6371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
6381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int reserve_mem_region(soinfo *si)
6401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
6411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    void *base = mmap((void *)si->base, si->size, PROT_READ | PROT_EXEC,
6421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
6431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (base == MAP_FAILED) {
6441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        ERROR("%5d can NOT map (%sprelinked) library '%s' at 0x%08x "
6451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              "as requested, will try general pool: %d (%s)\n",
6461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, (si->base ? "" : "non-"), si->name, si->base,
6471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              errno, strerror(errno));
6481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return -1;
6491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    } else if (base != (void *)si->base) {
6501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        ERROR("OOPS: %5d %sprelinked library '%s' mapped at 0x%08x, "
6511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              "not at 0x%08x\n", pid, (si->base ? "" : "non-"),
6521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              si->name, (unsigned)base, si->base);
6531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        munmap(base, si->size);
6541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return -1;
6551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
6571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
6581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int
6601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectalloc_mem_region(soinfo *si)
6611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
6621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->base) {
6631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* Attempt to mmap a prelinked library. */
6641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->ba_index = -1;
6651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return reserve_mem_region(si);
6661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* This is not a prelinked library, so we attempt to allocate space
6691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       for it from the buddy allocator, which manages the area between
6701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       LIBBASE and LIBLAST.
6711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    */
6721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->ba_index = ba_allocate(si->size);
6731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si->ba_index >= 0) {
6741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->base = ba_start_addr(si->ba_index);
6751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        PRINT("%5d mapping library '%s' at %08x (index %d) " \
6761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              "through buddy allocator.\n",
6771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, si->name, si->base, si->ba_index);
6781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (reserve_mem_region(si) < 0) {
6791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ba_free(si->ba_index);
6801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->ba_index = -1;
6811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->base = 0;
6821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            goto err;
6831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
6841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return 0;
6851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
6861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecterr:
6881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    ERROR("OOPS: %5d cannot map library '%s'. no vspace available.\n",
6891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          pid, si->name);
6901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
6911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
6921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define MAYBE_MAP_FLAG(x,from,to)    (((x) & (from)) ? (to) : 0)
6941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define PFLAGS_TO_PROT(x)            (MAYBE_MAP_FLAG((x), PF_X, PROT_EXEC) | \
6951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                      MAYBE_MAP_FLAG((x), PF_R, PROT_READ) | \
6961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                      MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE))
6971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* load_segments
6981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
6991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     This function loads all the loadable (PT_LOAD) segments into memory
7001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     at their appropriate memory offsets off the base address.
7011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
7021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Args:
7031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     fd: Open file descriptor to the library to load.
7041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     header: Pointer to a header page that contains the ELF header.
7051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *             This is needed since we haven't mapped in the real file yet.
7061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     si: ptr to soinfo struct describing the shared object.
7071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
7081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Returns:
7091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *     0 on success, -1 on failure.
7101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
7111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int
7121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectload_segments(int fd, void *header, soinfo *si)
7131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
7141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Ehdr *ehdr = (Elf32_Ehdr *)header;
7151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Phdr *phdr = (Elf32_Phdr *)((unsigned char *)header + ehdr->e_phoff);
7161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *base = (unsigned char *)si->base;
7171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int cnt;
7181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned len;
7191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *tmp;
7201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *pbase;
7211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned char *extra_base;
7221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned extra_len;
7231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned total_sz = 0;
7241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->wrprotect_start = 0xffffffff;
7261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->wrprotect_end = 0;
7271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d - Begin loading segments for '%s' @ 0x%08x ]\n",
7291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          pid, si->name, (unsigned)si->base);
7301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Now go through all the PT_LOAD segments and map them into memory
7311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * at the appropriate locations. */
7321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (cnt = 0; cnt < ehdr->e_phnum; ++cnt, ++phdr) {
7331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (phdr->p_type == PT_LOAD) {
7341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG_DUMP_PHDR(phdr, "PT_LOAD", pid);
7351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* we want to map in the segment on a page boundary */
7361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            tmp = base + (phdr->p_vaddr & (~PAGE_MASK));
7371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* add the # of bytes we masked off above to the total length. */
7381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            len = phdr->p_filesz + (phdr->p_vaddr & PAGE_MASK);
7391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE("[ %d - Trying to load segment from '%s' @ 0x%08x "
7411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  "(0x%08x). p_vaddr=0x%08x p_offset=0x%08x ]\n", pid, si->name,
7421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  (unsigned)tmp, len, phdr->p_vaddr, phdr->p_offset);
7431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            pbase = mmap(tmp, len, PFLAGS_TO_PROT(phdr->p_flags),
7441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                         MAP_PRIVATE | MAP_FIXED, fd,
7451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                         phdr->p_offset & (~PAGE_MASK));
7461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (pbase == MAP_FAILED) {
7471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                ERROR("%d failed to map segment from '%s' @ 0x%08x (0x%08x). "
7481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      "p_vaddr=0x%08x p_offset=0x%08x\n", pid, si->name,
7491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      (unsigned)tmp, len, phdr->p_vaddr, phdr->p_offset);
7501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                goto fail;
7511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
7521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* If 'len' didn't end on page boundary, and it's a writable
7541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * segment, zero-fill the rest. */
7551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if ((len & PAGE_MASK) && (phdr->p_flags & PF_W))
7561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                memset((void *)(pbase + len), 0, PAGE_SIZE - (len & PAGE_MASK));
7571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* Check to see if we need to extend the map for this segment to
7591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * cover the diff between filesz and memsz (i.e. for bss).
7601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *
7611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  base           _+---------------------+  page boundary
7621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  .                     .
7631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  |                     |
7641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  .                     .
7651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  pbase          _+---------------------+  page boundary
7661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  |                     |
7671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  .                     .
7681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  base + p_vaddr _|                     |
7691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  . \          \        .
7701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  . | filesz   |        .
7711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  pbase + len    _| /          |        |
7721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *     <0 pad>      .            .        .
7731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  extra_base     _+------------|--------+  page boundary
7741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               /  .            .        .
7751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               |  .            .        .
7761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               |  +------------|--------+  page boundary
7771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *  extra_len->  |  |            |        |
7781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               |  .            | memsz  .
7791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               |  .            |        .
7801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *               \ _|            /        |
7811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  .                     .
7821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                  |                     |
7831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *                 _+---------------------+  page boundary
7841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             */
7851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            tmp = (unsigned char *)(((unsigned)pbase + len + PAGE_SIZE - 1) &
7861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                    (~PAGE_MASK));
7871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (tmp < (base + phdr->p_vaddr + phdr->p_memsz)) {
7881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                extra_len = base + phdr->p_vaddr + phdr->p_memsz - tmp;
7891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                TRACE("[ %5d - Need to extend segment from '%s' @ 0x%08x "
7901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      "(0x%08x) ]\n", pid, si->name, (unsigned)tmp, extra_len);
7911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* map in the extra page(s) as anonymous into the range.
7921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * This is probably not necessary as we already mapped in
7931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * the entire region previously, but we just want to be
7941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * sure. This will also set the right flags on the region
7951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * (though we can probably accomplish the same thing with
7961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * mprotect).
7971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 */
7981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                extra_base = mmap((void *)tmp, extra_len,
7991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                  PFLAGS_TO_PROT(phdr->p_flags),
8001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                  MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS,
8011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                  -1, 0);
8021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (extra_base == MAP_FAILED) {
8031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    ERROR("[ %5d - failed to extend segment from '%s' @ 0x%08x "
8041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                          "(0x%08x) ]\n", pid, si->name, (unsigned)tmp,
8051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                          extra_len);
8061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    goto fail;
8071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                }
8081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* TODO: Check if we need to memset-0 this region.
8091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * Anonymous mappings are zero-filled copy-on-writes, so we
8101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * shouldn't need to. */
8111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                TRACE("[ %5d - Segment from '%s' extended @ 0x%08x "
8121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      "(0x%08x)\n", pid, si->name, (unsigned)extra_base,
8131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      extra_len);
8141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
8151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* set the len here to show the full extent of the segment we
8161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * just loaded, mostly for debugging */
8171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            len = (((unsigned)base + phdr->p_vaddr + phdr->p_memsz +
8181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    PAGE_SIZE - 1) & (~PAGE_MASK)) - (unsigned)pbase;
8191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE("[ %5d - Successfully loaded segment from '%s' @ 0x%08x "
8201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  "(0x%08x). p_vaddr=0x%08x p_offset=0x%08x\n", pid, si->name,
8211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  (unsigned)pbase, len, phdr->p_vaddr, phdr->p_offset);
8221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            total_sz += len;
8231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* Make the section writable just in case we'll have to write to
8241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * it during relocation (i.e. text segment). However, we will
8251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * remember what range of addresses should be write protected.
8261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             *
8271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             */
8281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (!(phdr->p_flags & PF_W)) {
8291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if ((unsigned)pbase < si->wrprotect_start)
8301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    si->wrprotect_start = (unsigned)pbase;
8311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (((unsigned)pbase + len) > si->wrprotect_end)
8321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    si->wrprotect_end = (unsigned)pbase + len;
8331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                mprotect(pbase, len,
8341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                         PFLAGS_TO_PROT(phdr->p_flags) | PROT_WRITE);
8351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
8361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } else if (phdr->p_type == PT_DYNAMIC) {
8371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG_DUMP_PHDR(phdr, "PT_DYNAMIC", pid);
8381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* this segment contains the dynamic linking information */
8391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->dynamic = (unsigned *)(base + phdr->p_vaddr);
8401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } else {
8411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifdef ANDROID_ARM_LINKER
8421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (phdr->p_type == PT_ARM_EXIDX) {
8431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                DEBUG_DUMP_PHDR(phdr, "PT_ARM_EXIDX", pid);
8441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* exidx entries (used for stack unwinding) are 8 bytes each.
8451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 */
8461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->ARM_exidx = (unsigned *)phdr->p_vaddr;
8471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->ARM_exidx_count = phdr->p_memsz / 8;
8481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
8491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
8501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
8511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
8531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Sanity check */
8551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (total_sz > si->size) {
8561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        ERROR("%5d - Total length (0x%08x) of mapped segments from '%s' is "
8571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              "greater than what was allocated (0x%08x). THIS IS BAD!\n",
8581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, total_sz, si->name, si->size);
8591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
8601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
8611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d - Finish loading segments for '%s' @ 0x%08x. "
8631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          "Total memory footprint: 0x%08x bytes ]\n", pid, si->name,
8641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          (unsigned)si->base, si->size);
8651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
8661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectfail:
8681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* We can just blindly unmap the entire region even though some things
8691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * were mapped in originally with anonymous and others could have been
8701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * been mapped in from the file before we failed. The kernel will unmap
8711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * all the pages in the range, irrespective of how they got there.
8721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
8731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    munmap((void *)si->base, si->size);
8741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags |= FLAG_ERROR;
8751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
8761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
8771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* TODO: Implement this to take care of the fact that Android ARM
8791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ELF objects shove everything into a single loadable segment that has the
8801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * write bit set. wr_offset is then used to set non-(data|bss) pages to be
8811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * non-writable.
8821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
8831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
8841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic unsigned
8851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectget_wr_offset(int fd, const char *name, Elf32_Ehdr *ehdr)
8861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
8871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Shdr *shdr_start;
8881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Shdr *shdr;
8891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int shdr_sz = ehdr->e_shnum * sizeof(Elf32_Shdr);
8901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int cnt;
8911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned wr_offset = 0xffffffff;
8921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    shdr_start = mmap(0, shdr_sz, PROT_READ, MAP_PRIVATE, fd,
8941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      ehdr->e_shoff & (~PAGE_MASK));
8951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (shdr_start == MAP_FAILED) {
8961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        WARN("%5d - Could not read section header info from '%s'. Will not "
8971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             "not be able to determine write-protect offset.\n", pid, name);
8981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return (unsigned)-1;
8991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
9001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(cnt = 0, shdr = shdr_start; cnt < ehdr->e_shnum; ++cnt, ++shdr) {
9021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if ((shdr->sh_type != SHT_NULL) && (shdr->sh_flags & SHF_WRITE) &&
9031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            (shdr->sh_addr < wr_offset)) {
9041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            wr_offset = shdr->sh_addr;
9051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
9061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
9071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    munmap(shdr_start, shdr_sz);
9091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return wr_offset;
9101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
9111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
9121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *
9141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectload_library(const char *name)
9151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
9161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int fd = open_library(name);
9171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int cnt;
9181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned ext_sz;
9191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned req_base;
9201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si = NULL;
9211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Ehdr *hdr;
9221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(fd == -1)
9241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return NULL;
9251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* We have to read the ELF header to figure out what to do with this image
9271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
9281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (lseek(fd, 0, SEEK_SET) < 0) {
9291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        ERROR("lseek() failed!\n");
9301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
9311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
9321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if ((cnt = read(fd, &__header[0], PAGE_SIZE)) < 0) {
9341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        ERROR("read() failed!\n");
9351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
9361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
9371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Parse the ELF header and get the size of the memory footprint for
9391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * the library */
9401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    req_base = get_lib_extents(fd, name, &__header[0], &ext_sz);
9411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (req_base == (unsigned)-1)
9421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
9431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d - '%s' (%s) wants base=0x%08x sz=0x%08x ]\n", pid, name,
9441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          (req_base ? "prelinked" : "not pre-linked"), req_base, ext_sz);
9451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Now configure the soinfo struct where we'll store all of our data
9471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * for the ELF object. If the loading fails, we waste the entry, but
9481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * same thing would happen if we failed during linking. Configuring the
9491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * soinfo struct here is a lot more convenient.
9501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
9511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si = alloc_info(name);
9521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si == NULL)
9531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
9541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Carve out a chunk of memory where we will map in the individual
9561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * segments */
9571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->base = req_base;
9581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->size = ext_sz;
9591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags = 0;
9601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->entry = 0;
9611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->dynamic = (unsigned *)-1;
9621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (alloc_mem_region(si) < 0)
9631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
9641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d allocated memory for %s @ %p (0x%08x) ]\n",
9661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          pid, name, (void *)si->base, (unsigned) ext_sz);
9671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Now actually load the library's segments into right places in memory */
9691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (load_segments(fd, &__header[0], si) < 0) {
9701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (si->ba_index >= 0) {
9711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ba_free(si->ba_index);
9721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->ba_index = -1;
9731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
9741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
9751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
9761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* this might not be right. Technically, we don't even need this info
9781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * once we go through 'load_segments'. */
9791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    hdr = (Elf32_Ehdr *)si->base;
9801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->phdr = (Elf32_Phdr *)((unsigned char *)si->base + hdr->e_phoff);
9811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->phnum = hdr->e_phnum;
9821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /**/
9831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    close(fd);
9851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si;
9861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectfail:
9881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si) free_info(si);
9891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    close(fd);
9901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return NULL;
9911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
9921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic soinfo *
9941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectinit_library(soinfo *si)
9951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
9961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned wr_offset = 0xffffffff;
9971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* At this point we know that whatever is loaded @ base is a valid ELF
9991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * shared library whose segments are properly mapped in. */
10001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d init_library base=0x%08x sz=0x%08x name='%s') ]\n",
10011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          pid, si->base, si->size, si->name);
10021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->base < LIBBASE || si->base >= LIBLAST)
10041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->flags |= FLAG_PRELINKED;
10051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(link_image(si, wr_offset)) {
10071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* We failed to link.  However, we can only restore libbase
10081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ** if no additional libraries have moved it since we updated it.
10091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            */
10101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        munmap((void *)si->base, si->size);
10111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return NULL;
10121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
10131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si;
10151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
10161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectsoinfo *find_library(const char *name)
10181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
10191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
10201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(si = solist; si != 0; si = si->next){
10221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(!strcmp(name, si->name)) {
10231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(si->flags & FLAG_ERROR) return 0;
10241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(si->flags & FLAG_LINKED) return si;
10251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ERROR("OOPS: %5d recursive link to '%s'\n", pid, si->name);
10261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return 0;
10271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
10281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
10291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d '%s' has not been loaded yet.  Locating...]\n", pid, name);
10311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si = load_library(name);
10321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si == NULL)
10331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return NULL;
10341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return init_library(si);
10351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
10361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* TODO:
10381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   notify gdb of unload
10391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *   for non-prelinked libraries, find a way to decrement libbase
10401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
10411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void call_destructors(soinfo *si);
10421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectunsigned unload_library(soinfo *si)
10431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
10441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned *d;
10451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->refcount == 1) {
10461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("%5d unloading '%s'\n", pid, si->name);
10471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        call_destructors(si);
10481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for(d = si->dynamic; *d; d += 2) {
10501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(d[0] == DT_NEEDED){
10511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                TRACE("%5d %s needs to unload %s\n", pid,
10521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      si->name, si->strtab + d[1]);
10531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                soinfo *lsi = find_library(si->strtab + d[1]);
10541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if(lsi)
10551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    unload_library(lsi);
10561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                else
10571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    ERROR("%5d could not unload '%s'\n",
10581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                          pid, si->strtab + d[1]);
10591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
10601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
10611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        munmap((char *)si->base, si->size);
10631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (si->ba_index >= 0) {
10641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            PRINT("%5d releasing library '%s' address space at %08x "\
10651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  "through buddy allocator.\n",
10661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->base);
10671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ba_free(si->ba_index);
10681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
10691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        free_info(si);
10701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->refcount = 0;
10711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
10721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    else {
10731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->refcount--;
10741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        PRINT("%5d not unloading '%s', decrementing refcount to %d\n",
10751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, si->name, si->refcount);
10761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
10771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si->refcount;
10781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
10791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* TODO: don't use unsigned for addrs below. It works, but is not
10811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ideal. They should probably be either uint32_t, Elf32_Addr, or unsigned
10821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * long.
10831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
10841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int reloc_library(soinfo *si, Elf32_Rel *rel, unsigned count)
10851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
10861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *symtab = si->symtab;
10871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    const char *strtab = si->strtab;
10881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Sym *s;
10891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned base;
10901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Rel *start = rel;
10911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned idx;
10921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (idx = 0; idx < count; ++idx) {
10941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned type = ELF32_R_TYPE(rel->r_info);
10951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned sym = ELF32_R_SYM(rel->r_info);
10961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned reloc = (unsigned)(rel->r_offset + si->base);
10971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned sym_addr = 0;
10981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        char *sym_name = NULL;
10991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        DEBUG("%5d Processing '%s' relocation at index %d\n", pid,
11011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              si->name, idx);
11021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(sym != 0) {
11031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            s = _do_lookup(si, strtab + symtab[sym].st_name, &base);
11041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(s == 0) {
11051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                ERROR("%5d cannot locate '%s'...\n", pid, sym_name);
11061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return -1;
11071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
11081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
11091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if((base == 0) && (si->base != 0)){
11101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    /* linking from libraries to main image is bad */
11111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                ERROR("%5d cannot locate '%s'...\n",
11121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       pid, strtab + symtab[sym].st_name);
11131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return -1;
11141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
11151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
11161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if ((s->st_shndx == SHN_UNDEF) && (s->st_value != 0)) {
11171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                ERROR("%5d In '%s', shndx=%d && value=0x%08x. We do not "
11181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      "handle this yet\n", pid, si->name, s->st_shndx,
11191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                      s->st_value);
11201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return -1;
11211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
11221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            sym_addr = (unsigned)(s->st_value + base);
11231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            sym_name = (char *)(strtab + symtab[sym].st_name);
11241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_SYMBOL);
11251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } else {
11261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            s = 0;
11271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
11281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* TODO: This is ugly. Split up the relocations by arch into
11301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * different files.
11311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
11321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        switch(type){
11331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if defined(ANDROID_ARM_LINKER)
11341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_JUMP_SLOT:
11351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
11361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
11371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO JMP_SLOT %08x <- %08x %s\n", pid,
11381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
11391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) = sym_addr;
11401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
11411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_GLOB_DAT:
11421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
11431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
11441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO GLOB_DAT %08x <- %08x %s\n", pid,
11451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
11461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) = sym_addr;
11471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
11481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_ABS32:
11491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
11501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
11511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO ABS %08x <- %08x %s\n", pid,
11521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
11531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) += sym_addr;
11541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
11551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#elif defined(ANDROID_X86_LINKER)
11561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_JUMP_SLOT:
11571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
11581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
11591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO JMP_SLOT %08x <- %08x %s\n", pid,
11601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
11611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) = sym_addr;
11621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
11631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_GLOB_DAT:
11641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_ABSOLUTE);
11651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
11661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO GLOB_DAT %08x <- %08x %s\n", pid,
11671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
11681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) = sym_addr;
11691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
11701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif /* ANDROID_*_LINKER */
11711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if defined(ANDROID_ARM_LINKER)
11731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_RELATIVE:
11741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#elif defined(ANDROID_X86_LINKER)
11751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_RELATIVE:
11761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif /* ANDROID_*_LINKER */
11771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_RELATIVE);
11781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
11791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(sym){
11801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                ERROR("%5d odd RELATIVE form...\n", pid);
11811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return -1;
11821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
11831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO RELATIVE %08x <- +%08x\n", pid,
11841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, si->base);
11851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned*)reloc) += si->base;
11861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
11871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if defined(ANDROID_X86_LINKER)
11891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_32:
11901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_RELATIVE);
11911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
11921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO R_386_32 %08x <- +%08x %s\n", pid,
11941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, sym_addr, sym_name);
11951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned *)reloc) += (unsigned)sym_addr;
11961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
11971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_386_PC32:
11991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_RELATIVE);
12001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
12011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO R_386_PC32 %08x <- "
12021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       "+%08x (%08x - %08x) %s\n", pid, reloc,
12031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       (sym_addr - reloc), sym_addr, reloc, sym_name);
12041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *((unsigned *)reloc) += (unsigned)(sym_addr - reloc);
12051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
12061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif /* ANDROID_X86_LINKER */
12071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifdef ANDROID_ARM_LINKER
12091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case R_ARM_COPY:
12101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            COUNT_RELOC(RELOC_COPY);
12111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            MARK(rel->r_offset);
12121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            TRACE_TYPE(RELO, "%5d RELO %08x <- %d @ %08x %s\n", pid,
12131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                       reloc, s->st_size, sym_addr, sym_name);
12141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            memcpy((void*)reloc, (void*)sym_addr, s->st_size);
12151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
12161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif /* ANDROID_ARM_LINKER */
12171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        default:
12191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ERROR("%5d unknown reloc type %d @ %p (%d)\n",
12201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, type, rel, (int) (rel - start));
12211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return -1;
12221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
12231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        rel++;
12241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
12251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
12261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
12271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void call_array(unsigned *ctor, int count)
12291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
12301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int n;
12311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(n = count; n > 0; n--){
12321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Looking at ctor *0x%08x == 0x%08x ]\n", pid,
12331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)ctor, (unsigned)*ctor);
12341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        void (*func)() = (void (*)()) *ctor++;
12351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(((int) func == 0) || ((int) func == -1)) continue;
12361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling func @ 0x%08x ]\n", pid, (unsigned)func);
12371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        func();
12381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
12391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
12401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void call_constructors(soinfo *si)
12421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
12431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* TODO: THE ORIGINAL CODE SEEMED TO CALL THE INIT FUNCS IN THE WRONG ORDER.
12441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     *       Old order: init, init_array, preinit_array..
12451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     *       Correct order: preinit_array, init, init_array.
12461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     *       Verify WHY.
12471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
12481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->flags & FLAG_EXE) {
12501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling preinit_array @ 0x%08x [%d] for '%s' ]\n",
12511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              pid, (unsigned)si->preinit_array, si->preinit_array_count,
12521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              si->name);
12531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        call_array(si->preinit_array, si->preinit_array_count);
12541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling preinit_array for '%s' ]\n", pid, si->name);
12551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    } else {
12561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (si->preinit_array) {
12571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ERROR("%5d Shared library '%s' has a preinit_array table @ 0x%08x."
12581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  " This is INVALID.\n", pid, si->name,
12591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  (unsigned)si->preinit_array);
12601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
12611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
12621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // If we have an init section, then we should call it now, to make sure
12641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // that all the funcs in the .ctors section get run.
12651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // Note: For ARM, we shouldn't have a .ctor section (should be empty)
12661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // when we have an (pre)init_array section, but let's be compatible with
12671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // old (non-eabi) binaries and try the _init (DT_INIT) anyway.
12681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->init_func) {
12691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling init_func @ 0x%08x for '%s' ]\n", pid,
12701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)si->init_func, si->name);
12711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->init_func();
12721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling init_func for '%s' ]\n", pid, si->name);
12731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
12741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->init_array) {
12761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling init_array @ 0x%08x [%d] for '%s' ]\n", pid,
12771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)si->init_array, si->init_array_count, si->name);
12781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        call_array(si->init_array, si->init_array_count);
12791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling init_array for '%s' ]\n", pid, si->name);
12801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
12811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
12821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void call_destructors(soinfo *si)
12841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
12851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->fini_array) {
12861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling fini_array @ 0x%08x [%d] for '%s' ]\n", pid,
12871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)si->fini_array, si->fini_array_count, si->name);
12881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        call_array(si->fini_array, si->fini_array_count);
12891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling fini_array for '%s' ]\n", pid, si->name);
12901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
12911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // If we have an fini section, then we should call it now, to make sure
12931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // that all the funcs in the .dtors section get run.
12941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // Note: For ARM, we shouldn't have a .dtor section (should be empty)
12951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // when we have an fini_array section, but let's be compatible with
12961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // old (non-eabi) binaries and try the _fini (DT_FINI) anyway.
12971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->fini_func) {
12981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Calling fini_func @ 0x%08x for '%s' ]\n", pid,
12991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project              (unsigned)si->fini_func, si->name);
13001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->fini_func();
13011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Done calling fini_func for '%s' ]\n", pid, si->name);
13021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
13031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
13041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* Force any of the closed stdin, stdout and stderr to be associated with
13061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project   /dev/null. */
13071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int nullify_closed_stdio (void)
13081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
13091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int dev_null, i, status;
13101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int return_value = 0;
13111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    dev_null = open("/dev/null", O_RDWR);
13131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (dev_null < 0) {
13141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        ERROR("Cannot open /dev/null.\n");
13151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return -1;
13161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
13171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d Opened /dev/null file-descriptor=%d]\n", pid, dev_null);
13181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* If any of the stdio file descriptors is valid and not associated
13201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       with /dev/null, dup /dev/null to it.  */
13211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (i = 0; i < 3; i++) {
13221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* If it is /dev/null already, we are done. */
13231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (i == dev_null)
13241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            continue;
13251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Nullifying stdio file descriptor %d]\n", pid, i);
13271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* The man page of fcntl does not say that fcntl(..,F_GETFL)
13281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           can be interrupted but we do this just to be safe. */
13291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        do {
13301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          status = fcntl(i, F_GETFL);
13311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } while (status < 0 && errno == EINTR);
13321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* If file is openned, we are good. */
13341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (status >= 0)
13351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          continue;
13361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* The only error we allow is that the file descriptor does not
13381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           exist, in which case we dup /dev/null to it. */
13391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (errno != EBADF) {
13401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ERROR("nullify_stdio: unhandled error %s\n", strerror(errno));
13411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return_value = -1;
13421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            continue;
13431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
13441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* Try dupping /dev/null to this stdio file descriptor and
13461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           repeat if there is a signal.  Note that any errors in closing
13471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           the stdio descriptor are lost.  */
13481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        do {
13491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            status = dup2(dev_null, i);
13501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } while (status < 0 && errno == EINTR);
13511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (status < 0) {
13531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ERROR("nullify_stdio: dup2 error %s\n", strerror(errno));
13541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return_value = -1;
13551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            continue;
13561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
13571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
13581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* If /dev/null is not one of the stdio file descriptors, close it. */
13601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (dev_null > 2) {
13611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        TRACE("[ %5d Closing /dev/null file-descriptor=%d]\n", pid, dev_null);
13621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	do {
13631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            status = close(dev_null);
13641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } while (status < 0 && errno == EINTR);
13651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (status < 0) {
13671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ERROR("nullify_stdio: close error %s\n", strerror(errno));
13681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return_value = -1;
13691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
13701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
13711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return return_value;
13731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
13741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic int link_image(soinfo *si, unsigned wr_offset)
13761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
13771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned *d;
13781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    Elf32_Phdr *phdr = si->phdr;
13791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int phnum = si->phnum;
13801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    INFO("[ %5d linking %s ]\n", pid, si->name);
13821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("%5d si->base = 0x%08x si->flags = 0x%08x\n", pid,
13831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          si->base, si->flags);
13841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->flags & FLAG_EXE) {
13861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* Locate the needed program segments (DYNAMIC/ARM_EXIDX) for
13871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * linkage info if this is the executable. If this was a
13881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * dynamic lib, that would have been done at load time.
13891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         *
13901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * TODO: It's unfortunate that small pieces of this are
13911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * repeated from the load_library routine. Refactor this just
13921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * slightly to reuse these bits.
13931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         */
13941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        si->size = 0;
13951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for(; phnum > 0; --phnum, ++phdr) {
13961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#ifdef ANDROID_ARM_LINKER
13971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(phdr->p_type == PT_ARM_EXIDX) {
13981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* exidx entries (used for stack unwinding) are 8 bytes each.
13991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 */
14001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->ARM_exidx = (unsigned *)phdr->p_vaddr;
14011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->ARM_exidx_count = phdr->p_memsz / 8;
14021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
14031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
14041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (phdr->p_type == PT_LOAD) {
14051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* For the executable, we use the si->size field only in
14061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   dl_unwind_find_exidx(), so the meaning of si->size
14071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   is not the size of the executable; it is the last
14081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   virtual address of the loadable part of the executable;
14091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   since si->base == 0 for an executable, we use the
14101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   range [0, si->size) to determine whether a PC value
14111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   falls within the executable section.  Of course, if
14121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   a value is below phdr->p_vaddr, it's not in the
14131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   executable section, but a) we shouldn't be asking for
14141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   such a value anyway, and b) if we have to provide
14151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   an EXIDX for such a value, then the executable's
14161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                   EXIDX is probably the better choice.
14171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                */
14181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                DEBUG_DUMP_PHDR(phdr, "PT_LOAD", pid);
14191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (phdr->p_vaddr + phdr->p_memsz > si->size)
14201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    si->size = phdr->p_vaddr + phdr->p_memsz;
14211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* try to remember what range of addresses should be write
14221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 * protected */
14231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (!(phdr->p_flags & PF_W)) {
14241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    unsigned _end;
14251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    if (phdr->p_vaddr < si->wrprotect_start)
14271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                        si->wrprotect_start = phdr->p_vaddr;
14281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    _end = (((phdr->p_vaddr + phdr->p_memsz + PAGE_SIZE - 1) &
14291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                             (~PAGE_MASK)));
14301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    if (_end > si->wrprotect_end)
14311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                        si->wrprotect_end = _end;
14321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                }
14331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            } else if (phdr->p_type == PT_DYNAMIC) {
14341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (si->dynamic != (unsigned *)-1) {
14351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    ERROR("%5d multiple PT_DYNAMIC segments found in '%s'. "
14361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                          "Segment at 0x%08x, previously one found at 0x%08x\n",
14371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                          pid, si->name, si->base + phdr->p_vaddr,
14381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                          (unsigned)si->dynamic);
14391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    goto fail;
14401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                }
14411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                DEBUG_DUMP_PHDR(phdr, "PT_DYNAMIC", pid);
14421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                si->dynamic = (unsigned *) (si->base + phdr->p_vaddr);
14431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
14441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
14451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
14461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->dynamic == (unsigned *)-1) {
14481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        ERROR("%5d missing PT_DYNAMIC?!\n", pid);
14491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
14501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
14511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("%5d dynamic = %p\n", pid, si->dynamic);
14531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* extract useful information from dynamic section */
14551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(d = si->dynamic; *d; d++){
14561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        DEBUG("%5d d = %p, d[0] = 0x%08x d[1] = 0x%08x\n", pid, d, d[0], d[1]);
14571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        switch(*d++){
14581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_HASH:
14591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->nbucket = ((unsigned *) (si->base + *d))[0];
14601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->nchain = ((unsigned *) (si->base + *d))[1];
14611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->bucket = (unsigned *) (si->base + *d + 8);
14621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->chain = (unsigned *) (si->base + *d + 8 + si->nbucket * 4);
14631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
14641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_STRTAB:
14651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->strtab = (const char *) (si->base + *d);
14661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
14671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_SYMTAB:
14681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->symtab = (Elf32_Sym *) (si->base + *d);
14691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
14701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PLTREL:
14711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(*d != DT_REL) {
14721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                ERROR("DT_RELA not supported\n");
14731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                goto fail;
14741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
14751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
14761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_JMPREL:
14771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->plt_rel = (Elf32_Rel*) (si->base + *d);
14781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
14791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PLTRELSZ:
14801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->plt_rel_count = *d / 8;
14811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
14821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_REL:
14831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->rel = (Elf32_Rel*) (si->base + *d);
14841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
14851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_RELSZ:
14861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->rel_count = *d / 8;
14871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
14881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PLTGOT:
14891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* Save this in case we decide to do lazy binding. We don't yet. */
14901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->plt_got = (unsigned *)(si->base + *d);
14911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
14921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_DEBUG:
14931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            // Set the DT_DEBUG entry to the addres of _r_debug for GDB
14941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            *d = (int) &_r_debug;
14951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
14961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_RELA:
14971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ERROR("%5d DT_RELA not supported\n", pid);
14981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            goto fail;
14991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_INIT:
15001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->init_func = (void (*)(void))(si->base + *d);
15011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s constructors (init func) found at %p\n",
15021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->init_func);
15031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_FINI:
15051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->fini_func = (void (*)(void))(si->base + *d);
15061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s destructors (fini func) found at %p\n",
15071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->fini_func);
15081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_INIT_ARRAY:
15101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->init_array = (unsigned *)(si->base + *d);
15111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s constructors (init_array) found at %p\n",
15121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->init_array);
15131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_INIT_ARRAYSZ:
15151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->init_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
15161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_FINI_ARRAY:
15181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->fini_array = (unsigned *)(si->base + *d);
15191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s destructors (fini_array) found at %p\n",
15201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->fini_array);
15211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_FINI_ARRAYSZ:
15231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->fini_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
15241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PREINIT_ARRAY:
15261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->preinit_array = (unsigned *)(si->base + *d);
15271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s constructors (preinit_array) found at %p\n",
15281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid, si->name, si->preinit_array);
15291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_PREINIT_ARRAYSZ:
15311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->preinit_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
15321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case DT_TEXTREL:
15341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* TODO: make use of this. */
15351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            /* this means that we might have to write into where the text
15361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * segment was loaded during relocation... Do something with
15371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             * it.
15381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project             */
15391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d Text segment should be writable during relocation.\n",
15401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                  pid);
15411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
15421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
15431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
15441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("%5d si->base = 0x%08x, si->strtab = %p, si->symtab = %p\n",
15461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           pid, si->base, si->strtab, si->symtab);
15471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if((si->strtab == 0) || (si->symtab == 0)) {
15491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        ERROR("%5d missing essential tables\n", pid);
15501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        goto fail;
15511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
15521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for(d = si->dynamic; *d; d += 2) {
15541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(d[0] == DT_NEEDED){
15551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            DEBUG("%5d %s needs %s\n", pid, si->name, si->strtab + d[1]);
15561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            soinfo *lsi = find_library(si->strtab + d[1]);
15571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(lsi == 0) {
15581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                ERROR("%5d could not load '%s'\n", pid, si->strtab + d[1]);
15591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                goto fail;
15601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
15611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            lsi->refcount++;
15621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
15631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
15641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si->plt_rel) {
15661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        DEBUG("[ %5d relocating %s plt ]\n", pid, si->name );
15671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(reloc_library(si, si->plt_rel, si->plt_rel_count))
15681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            goto fail;
15691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
15701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si->rel) {
15711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        DEBUG("[ %5d relocating %s ]\n", pid, si->name );
15721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(reloc_library(si, si->rel, si->rel_count))
15731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            goto fail;
15741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
15751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags |= FLAG_LINKED;
15771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("[ %5d finished linking %s ]\n", pid, si->name);
15781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
15801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* This is the way that the old dynamic linker did protection of
15811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * non-writable areas. It would scan section headers and find where
15821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * .text ended (rather where .data/.bss began) and assume that this is
15831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * the upper range of the non-writable area. This is too coarse,
15841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * and is kept here for reference until we fully move away from single
15851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * segment elf objects. See the code in get_wr_offset (also #if'd 0)
15861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * that made this possible.
15871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
15881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(wr_offset < 0xffffffff){
15891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        mprotect((void*) si->base, wr_offset, PROT_READ | PROT_EXEC);
15901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
15911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#else
15921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* TODO: Verify that this does the right thing in all cases, as it
15931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * presently probably does not. It is possible that an ELF image will
15941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * come with multiple read-only segments. What we ought to do is scan
15951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * the program headers again and mprotect all the read-only segments.
15961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * To prevent re-scanning the program header, we would have to build a
15971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * list of loadable segments in si, and then scan that instead. */
15981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (si->wrprotect_start != 0xffffffff && si->wrprotect_end != 0) {
15991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        mprotect((void *)si->wrprotect_start,
16001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 si->wrprotect_end - si->wrprotect_start,
16011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                 PROT_READ | PROT_EXEC);
16021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
16041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* If this is a SET?ID program, dup /dev/null to opened stdin,
16061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project       stdout and stderr to close a security hole described in:
16071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc
16091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     */
16111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (getuid() != geteuid() || getgid() != getegid())
16121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        nullify_closed_stdio ();
16131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    call_constructors(si);
16141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    notify_gdb_of_load(si);
16151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
16161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectfail:
16181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    ERROR("failed to link %s\n", si->name);
16191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags |= FLAG_ERROR;
16201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return -1;
16211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
16221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint main(int argc, char **argv)
16241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
16251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
16261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
16271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define ANDROID_TLS_SLOTS  BIONIC_TLS_SLOTS
16291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void * __tls_area[ANDROID_TLS_SLOTS];
16311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectunsigned __linker_init(unsigned **elfdata)
16331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
16341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    static soinfo linker_soinfo;
16351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int argc = (int) *elfdata;
16371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    char **argv = (char**) (elfdata + 1);
16381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    unsigned *vecs = (unsigned*) (argv + argc + 1);
16391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    soinfo *si;
16401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct link_map * map;
16411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    pid = getpid();
16431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING
16451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    struct timeval t0, t1;
16461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    gettimeofday(&t0, 0);
16471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
16481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    __set_tls(__tls_area);
16501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    ((unsigned *)__get_tls())[TLS_SLOT_THREAD_ID] = gettid();
16511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    debugger_init();
16531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* skip past the environment */
16551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    while(vecs[0] != 0) {
16561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if(!strncmp((char*) vecs[0], "DEBUG=", 6)) {
16571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            debug_verbosity = atoi(((char*) vecs[0]) + 6);
16581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
16591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        vecs++;
16601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    vecs++;
16621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    INFO("[ android linker & debugger ]\n");
16641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    DEBUG("%5d elfdata @ 0x%08x\n", pid, (unsigned)elfdata);
16651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si = alloc_info(argv[0]);
16671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(si == 0) {
16681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        exit(-1);
16691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
16701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* bootstrap the link map, the main exe always needs to be first */
16721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->flags |= FLAG_EXE;
16731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map = &(si->linkmap);
16741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_addr = 0;
16761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_name = argv[0];
16771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_prev = NULL;
16781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    map->l_next = NULL;
16791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    _r_debug.r_map = map;
16811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    r_debug_tail = map;
16821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* gdb expects the linker to be in the debug shared object list,
16841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * and we need to make sure that the reported load address is zero.
16851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * Without this, gdb gets the wrong idea of where rtld_db_dlactivity()
16861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * is.  Don't use alloc_info(), because the linker shouldn't
16871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * be on the soinfo list.
16881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         */
16891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    strcpy((char*) linker_soinfo.name, "/system/bin/linker");
16901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    linker_soinfo.flags = 0;
16911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    linker_soinfo.base = 0;     // This is the important part; must be zero.
16921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    insert_soinfo_into_debug_map(&linker_soinfo);
16931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /* extract information passed from the kernel */
16951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    while(vecs[0] != 0){
16961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        switch(vecs[0]){
16971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case AT_PHDR:
16981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->phdr = (Elf32_Phdr*) vecs[1];
16991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
17001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case AT_PHNUM:
17011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->phnum = (int) vecs[1];
17021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
17031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        case AT_ENTRY:
17041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            si->entry = vecs[1];
17051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break;
17061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
17071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        vecs += 2;
17081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
17091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    ba_init();
17111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->base = 0;
17131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->dynamic = (unsigned *)-1;
17141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->wrprotect_start = 0xffffffff;
17151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    si->wrprotect_end = 0;
17161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if(link_image(si, 0)){
17181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        ERROR("CANNOT LINK EXECUTABLE '%s'\n", argv[0]);
17191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        exit(-1);
17201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
17211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING
17231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    gettimeofday(&t1,NULL);
17241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    PRINT("LINKER TIME: %s: %d microseconds\n", argv[0], (int) (
17251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
17261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec)
17271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project               ));
17281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
17291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if STATS
17301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    PRINT("RELO STATS: %s: %d abs, %d rel, %d copy, %d symbol\n", argv[0],
17311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           linker_stats.reloc[RELOC_ABSOLUTE],
17321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           linker_stats.reloc[RELOC_RELATIVE],
17331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           linker_stats.reloc[RELOC_COPY],
17341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project           linker_stats.reloc[RELOC_SYMBOL]);
17351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
17361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if COUNT_PAGES
17371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    {
17381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned n;
17391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned i;
17401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        unsigned count = 0;
17411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for(n = 0; n < 4096; n++){
17421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if(bitmask[n]){
17431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                unsigned x = bitmask[n];
17441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                for(i = 0; i < 8; i++){
17451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    if(x & 1) count++;
17461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    x >>= 1;
17471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                }
17481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
17491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
17501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        PRINT("PAGES MODIFIED: %s: %d (%dKB)\n", argv[0], count, count * 4);
17511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
17521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
17531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if TIMING || STATS || COUNT_PAGES
17551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    fflush(stdout);
17561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
17571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TRACE("[ %5d Ready to execute '%s' @ 0x%08x ]\n", pid, si->name,
17591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project          si->entry);
17601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return si->entry;
17611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
1762