Merge "Adding event logging to libc."
diff --git a/libc/Android.mk b/libc/Android.mk
index 596a856..70a5243 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -207,6 +207,7 @@
string/strxfrm.c \
string/__memcpy_chk.c \
string/__memmove_chk.c \
+ string/__memset_chk.c \
string/__strcat_chk.c \
string/__strcpy_chk.c \
string/__strncat_chk.c \
diff --git a/libc/include/string.h b/libc/include/string.h
index 12c9500..e1718e9 100644
--- a/libc/include/string.h
+++ b/libc/include/string.h
@@ -85,27 +85,21 @@
extern int strcoll(const char *, const char *) __purefunc;
extern size_t strxfrm(char *, const char *, size_t);
-#if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 && defined(__OPTIMIZE__) && __OPTIMIZE__ > 0
-
-#define __BIONIC_FORTIFY_INLINE \
- extern inline \
- __attribute__ ((always_inline)) \
- __attribute__ ((gnu_inline)) \
- __attribute__ ((artificial))
+#if defined(__BIONIC_FORTIFY_INLINE)
__BIONIC_FORTIFY_INLINE
void *memcpy (void *dest, const void *src, size_t len) {
- return __builtin___memcpy_chk (dest, src, len, __builtin_object_size (dest, 0));
+ return __builtin___memcpy_chk(dest, src, len, __builtin_object_size (dest, 0));
}
__BIONIC_FORTIFY_INLINE
void *memmove (void *dest, const void *src, size_t len) {
- return __builtin___memmove_chk (dest, src, len, __builtin_object_size (dest, 0));
+ return __builtin___memmove_chk(dest, src, len, __builtin_object_size (dest, 0));
}
__BIONIC_FORTIFY_INLINE
char *strcpy(char *dest, const char *src) {
- return __builtin___strcpy_chk (dest, src, __builtin_object_size (dest, 0));
+ return __builtin___strcpy_chk(dest, src, __builtin_object_size (dest, 0));
}
__BIONIC_FORTIFY_INLINE
@@ -115,7 +109,7 @@
__BIONIC_FORTIFY_INLINE
char *strcat(char *dest, const char *src) {
- return __builtin___strcat_chk (dest, src, __builtin_object_size (dest, 0));
+ return __builtin___strcat_chk(dest, src, __builtin_object_size (dest, 0));
}
__BIONIC_FORTIFY_INLINE
@@ -123,8 +117,12 @@
return __builtin___strncat_chk(dest, src, n, __builtin_object_size (dest, 0));
}
-#undef __BIONIC_FORTIFY_INLINE
-#endif
+__BIONIC_FORTIFY_INLINE
+void *memset (void *s, int c, size_t n) {
+ return __builtin___memset_chk(s, c, n, __builtin_object_size (s, 0));
+}
+
+#endif /* defined(__BIONIC_FORTIFY_INLINE) */
__END_DECLS
diff --git a/libc/include/strings.h b/libc/include/strings.h
index fee7dc4..db2aa3a 100644
--- a/libc/include/strings.h
+++ b/libc/include/strings.h
@@ -51,6 +51,14 @@
char *rindex(const char *, int);
int strcasecmp(const char *, const char *);
int strncasecmp(const char *, const char *, size_t);
+
+#if defined(__BIONIC_FORTIFY_INLINE)
+__BIONIC_FORTIFY_INLINE
+void bzero (void *s, size_t n) {
+ __builtin___memset_chk(s, '\0', n, __builtin_object_size (s, 0));
+}
+#endif /* defined(__BIONIC_FORTIFY_INLINE) */
+
__END_DECLS
#endif /* !defined(_STRINGS_H_) */
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index 71b419c..1ba9100 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -501,4 +501,12 @@
#define __BIONIC__ 1
#include <android/api-level.h>
+#if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 && defined(__OPTIMIZE__) && __OPTIMIZE__ > 0
+#define __BIONIC_FORTIFY_INLINE \
+ extern inline \
+ __attribute__ ((always_inline)) \
+ __attribute__ ((gnu_inline)) \
+ __attribute__ ((artificial))
+#endif
+
#endif /* !_SYS_CDEFS_H_ */
diff --git a/libc/string/__memset_chk.c b/libc/string/__memset_chk.c
new file mode 100644
index 0000000..1ccfd46
--- /dev/null
+++ b/libc/string/__memset_chk.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <private/logd.h>
+
+/*
+ * Runtime implementation of __builtin____memset_chk.
+ *
+ * See
+ * http://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html
+ * http://gcc.gnu.org/ml/gcc-patches/2004-09/msg02055.html
+ * for details.
+ *
+ * This memset check is called if _FORTIFY_SOURCE is defined and
+ * greater than 0.
+ */
+void *__memset_chk (void *dest, int c, size_t n, size_t dest_len)
+{
+ if (n > dest_len) {
+ __libc_android_log_print(ANDROID_LOG_FATAL, "libc",
+ "*** memset buffer overflow detected ***\n");
+ abort();
+ }
+
+ return memset(dest, c, n);
+}
diff --git a/libc/unistd/sysconf.c b/libc/unistd/sysconf.c
index 9377802..7caa4e9 100644
--- a/libc/unistd/sysconf.c
+++ b/libc/unistd/sysconf.c
@@ -25,16 +25,19 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <unistd.h>
-#include <sys/sysconf.h>
-#include <limits.h>
-#include <bionic_tls.h>
+
#include <asm/page.h>
-#include <stdio.h> /* for FOPEN_MAX */
+#include <bionic_tls.h>
+#include <ctype.h>
+#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h> // For FOPEN_MAX.
#include <string.h>
-#include <ctype.h>
+#include <sys/sysconf.h>
+#include <unistd.h>
/* seems to be the default on Linux, per the GLibc sources and my own digging */
@@ -62,18 +65,88 @@
#define SYSTEM_2_FORT_DEV -1 /* Fortran development unsupported */
#define SYSTEM_2_FORT_RUN -1 /* Fortran runtime unsupported */
#define SYSTEM_2_SW_DEV -1 /* posix software dev utilities unsupported */
-#define SYSTEM_2_LOCALEDEF -1 /* localdef() unimplemented */
+#define SYSTEM_2_LOCALEDEF -1 /* localedef() unimplemented */
#define SYSTEM_2_UPE -1 /* No UPE for you ! (User Portability Utilities) */
#define SYSTEM_2_VERSION -1 /* No posix command-line tools */
-static int __get_nproc_conf(void);
-static int __get_nproc_onln(void);
-static int __get_phys_pages(void);
-static int __get_avphys_pages(void);
+static bool __matches_cpuN(const char* s) {
+ // The %c trick is to ensure that we have the anchored match "^cpu[0-9]+$".
+ unsigned cpu;
+ char dummy;
+ return (sscanf(s, "cpu%u%c", &cpu, &dummy) == 1);
+}
-int
-sysconf( int name )
-{
+static int __get_nproc_conf(void) {
+ // On x86 kernels you can use /proc/cpuinfo for this, but on ARM kernels offline CPUs disappear
+ // from there. This method works on both.
+ DIR* d = opendir("/sys/devices/system/cpu");
+ if (!d) {
+ return 1;
+ }
+
+ int result = 0;
+ struct dirent de;
+ struct dirent* e;
+ while (!readdir_r(d, &de, &e) && e != NULL) {
+ if (e->d_type == DT_DIR && __matches_cpuN(e->d_name)) {
+ ++result;
+ }
+ }
+ closedir(d);
+ return result;
+}
+
+static int __get_nproc_onln(void) {
+ FILE* fp = fopen("/proc/stat", "r");
+ if (fp == NULL) {
+ return 1;
+ }
+
+ int result = 0;
+ char buf[256];
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ // Extract just the first word from the line.
+ // 'cpu0 7976751 1364388 3116842 469770388 8629405 0 49047 0 0 0'
+ char* p = strchr(buf, ' ');
+ if (p != NULL) {
+ *p = 0;
+ }
+ if (__matches_cpuN(buf)) {
+ ++result;
+ }
+ }
+ fclose(fp);
+ return result;
+}
+
+static int __get_meminfo(const char* pattern) {
+ FILE* fp = fopen("/proc/meminfo", "r");
+ if (fp == NULL) {
+ return -1;
+ }
+
+ int result = -1;
+ char buf[256];
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ long total;
+ if (sscanf(buf, pattern, &total) == 1) {
+ result = (int) (total / (PAGE_SIZE/1024));
+ break;
+ }
+ }
+ fclose(fp);
+ return result;
+}
+
+static int __get_phys_pages(void) {
+ return __get_meminfo("MemTotal: %ld kB");
+}
+
+static int __get_avphys_pages(void) {
+ return __get_meminfo("MemFree: %ld kB");
+}
+
+int sysconf(int name) {
switch (name) {
#ifdef _POSIX_ARG_MAX
case _SC_ARG_MAX: return _POSIX_ARG_MAX;
@@ -266,169 +339,3 @@
return -1;
}
}
-
-
-typedef struct {
- int rpos;
- int len;
- int overflow;
- int fd;
- int in_len;
- int in_pos;
- char buff[128];
- char input[128];
-} LineParser;
-
-static int
-line_parser_init( LineParser* p, const char* path )
-{
- p->rpos = 0;
- p->len = (int)sizeof(p->buff);
- p->overflow = 0;
-
- p->in_len = 0;
- p->in_pos = 0;
- p->fd = open( path, O_RDONLY );
-
- return p->fd;
-}
-
-
-static int
-line_parser_addc( LineParser* p, int c )
-{
- if (p->overflow) {
- p->overflow = (c == '\n');
- return 0;
- }
- if (p->rpos >= p->len) {
- p->overflow = 1;
- return 0;
- }
- if (c == '\n') {
- p->buff[p->rpos] = 0;
- p->rpos = 0;
- return 1;
- }
- p->buff[p->rpos++] = (char) c;
- return 0;
-}
-
-static int
-line_parser_getc( LineParser* p )
-{
- if (p->in_pos >= p->in_len) {
- int ret;
-
- p->in_len = p->in_pos = 0;
- do {
- ret = read(p->fd, p->input, sizeof(p->input));
- } while (ret < 0 && errno == EINTR);
-
- if (ret <= 0)
- return -1;
-
- p->in_len = ret;
- }
- return p->input[ p->in_pos++ ];
-}
-
-static const char*
-line_parser_gets( LineParser* p )
-{
- for (;;) {
- for (;;) {
- int c = line_parser_getc(p);
-
- if (c < 0) {
- close(p->fd);
- p->fd = -1;
- return NULL;
- }
- if (line_parser_addc(p, c))
- return p->buff;
- }
- }
-}
-
-static void
-line_parser_done( LineParser* p )
-{
- if (p->fd >= 0) {
- close(p->fd);
- p->fd = -1;
- }
-}
-
-static int
-__get_nproc_conf(void)
-{
- LineParser parser[1];
- const char* p;
- int count = 0;
-
- if (line_parser_init(parser, "/proc/cpuinfo") < 0)
- return 1;
-
- while ((p = line_parser_gets(parser))) {
- if ( !memcmp(p, "processor", 9) )
- count += 1;
- }
- return (count < 1) ? 1 : count;
-}
-
-
-static int
-__get_nproc_onln(void)
-{
- LineParser parser[1];
- const char* p;
- int count = 0;
-
- if (line_parser_init(parser, "/proc/stat") < 0)
- return 1;
-
- while ((p = line_parser_gets(parser))) {
- if ( !memcmp(p, "cpu", 3) && isdigit(p[3]) )
- count += 1;
- }
- return (count < 1) ? 1 : count;
-}
-
-static int
-__get_phys_pages(void)
-{
- LineParser parser[1];
- const char* p;
-
- if (line_parser_init(parser, "/proc/meminfo") < 0)
- return -2; /* what ? */
-
- while ((p = line_parser_gets(parser))) {
- long total;
- if ( sscanf(p, "MemTotal: %ld kB", &total) == 1 ) {
- line_parser_done(parser);
- return (int) (total / (PAGE_SIZE/1024));
- }
- }
- return -3;
-}
-
-static int
-__get_avphys_pages(void)
-{
- LineParser parser[1];
- const char* p;
-
- if (line_parser_init(parser, "/proc/meminfo") < 0)
- return -1; /* what ? */
-
- while ((p = line_parser_gets(parser))) {
- long total;
- if ( sscanf(p, "MemFree: %ld kB", &total) == 1 ) {
- line_parser_done(parser);
- return (int) (total / (PAGE_SIZE/1024));
- }
- }
- return -1;
-}
diff --git a/linker/linker.c b/linker/linker.c
index 739d3e4..be90fd7 100644
--- a/linker/linker.c
+++ b/linker/linker.c
@@ -347,7 +347,7 @@
for (si = solist; si != 0; si = si->next){
if ((addr >= si->base) && (addr < (si->base + si->size))) {
*pcount = si->ARM_exidx_count;
- return (_Unwind_Ptr)(si->base + (unsigned long)si->ARM_exidx);
+ return (_Unwind_Ptr)si->ARM_exidx;
}
}
*pcount = 0;
@@ -423,7 +423,7 @@
}
static Elf32_Sym *
-_do_lookup(soinfo *si, const char *name, unsigned *base)
+_do_lookup(soinfo *si, const char *name, unsigned *base, Elf32_Addr *offset)
{
unsigned elf_hash = elfhash(name);
Elf32_Sym *s;
@@ -486,9 +486,11 @@
done:
if(s != NULL) {
TRACE_TYPE(LOOKUP, "%5d si %s sym %s s->st_value = 0x%08x, "
- "found in %s, base = 0x%08x\n",
- pid, si->name, name, s->st_value, lsi->name, lsi->base);
+ "found in %s, base = 0x%08x, load offset = 0x%08x\n",
+ pid, si->name, name, s->st_value,
+ lsi->name, lsi->base, lsi->load_offset);
*base = lsi->base;
+ *offset = lsi->load_offset;
return s;
}
@@ -866,7 +868,8 @@
{
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)header;
Elf32_Phdr *phdr = (Elf32_Phdr *)((unsigned char *)header + ehdr->e_phoff);
- Elf32_Addr base = (Elf32_Addr) si->base;
+ Elf32_Phdr *phdr0 = 0; /* program header for the first LOAD segment */
+ Elf32_Addr base;
int cnt;
unsigned len;
Elf32_Addr tmp;
@@ -880,8 +883,27 @@
TRACE("[ %5d - Begin loading segments for '%s' @ 0x%08x ]\n",
pid, si->name, (unsigned)si->base);
+
+ for (cnt = 0; cnt < ehdr->e_phnum; ++cnt, ++phdr) {
+ if (phdr->p_type == PT_LOAD) {
+ phdr0 = phdr;
+ /*
+ * ELF specification section 2-2.
+ *
+ * PT_LOAD: "Loadable segment entries in the program
+ * header table appear in ascending order, sorted on the
+ * p_vaddr member."
+ */
+ si->load_offset = phdr->p_vaddr & (~PAGE_MASK);
+ break;
+ }
+ }
+ /* "base" might wrap around UINT32_MAX. */
+ base = (Elf32_Addr)(si->base - si->load_offset);
+
/* Now go through all the PT_LOAD segments and map them into memory
* at the appropriate locations. */
+ phdr = (Elf32_Phdr *)((unsigned char *)header + ehdr->e_phoff);
for (cnt = 0; cnt < ehdr->e_phnum; ++cnt, ++phdr) {
if (phdr->p_type == PT_LOAD) {
DEBUG_DUMP_PHDR(phdr, "PT_LOAD", pid);
@@ -991,9 +1013,9 @@
/* this segment contains the dynamic linking information */
si->dynamic = (unsigned *)(base + phdr->p_vaddr);
} else if (phdr->p_type == PT_GNU_RELRO) {
- if ((phdr->p_vaddr >= si->size)
- || ((phdr->p_vaddr + phdr->p_memsz) > si->size)
- || ((base + phdr->p_vaddr + phdr->p_memsz) < base)) {
+ if (((base + phdr->p_vaddr) >= si->base + si->size)
+ || ((base + phdr->p_vaddr + phdr->p_memsz) > si->base + si->size)
+ || ((base + phdr->p_vaddr + phdr->p_memsz) < si->base)) {
DL_ERR("%d invalid GNU_RELRO in '%s' "
"p_vaddr=0x%08x p_memsz=0x%08x", pid, si->name,
phdr->p_vaddr, phdr->p_memsz);
@@ -1007,7 +1029,7 @@
DEBUG_DUMP_PHDR(phdr, "PT_ARM_EXIDX", pid);
/* exidx entries (used for stack unwinding) are 8 bytes each.
*/
- si->ARM_exidx = (unsigned *)phdr->p_vaddr;
+ si->ARM_exidx = (unsigned *)(base + phdr->p_vaddr);
si->ARM_exidx_count = phdr->p_memsz / 8;
}
#endif
@@ -1023,6 +1045,21 @@
goto fail;
}
+ /* vaddr : Real virtual address in process' address space.
+ * p_vaddr : Relative virtual address in ELF object
+ * p_offset : File offset in ELF object
+ *
+ * vaddr p_vaddr p_offset
+ * ----- ------------ --------
+ * base 0
+ * si->base phdr0->p_vaddr & ~PAGE_MASK
+ * phdr0->p_vaddr phdr0->p_offset
+ * phdr ehdr->e_phoff
+ */
+ si->phdr = (Elf32_Phdr *)(base + phdr0->p_vaddr +
+ ehdr->e_phoff - phdr0->p_offset);
+ si->phnum = ehdr->e_phnum;
+
TRACE("[ %5d - Finish loading segments for '%s' @ 0x%08x. "
"Total memory footprint: 0x%08x bytes ]\n", pid, si->name,
(unsigned)si->base, si->size);
@@ -1143,9 +1180,6 @@
goto fail;
}
- si->phdr = (Elf32_Phdr *)((unsigned char *)si->base + hdr->e_phoff);
- si->phnum = hdr->e_phnum;
-
munmap(hdr, sb.st_size);
close(fd);
return si;
@@ -1282,13 +1316,14 @@
const char *strtab = si->strtab;
Elf32_Sym *s;
unsigned base;
+ Elf32_Addr offset;
Elf32_Rel *start = rel;
unsigned idx;
for (idx = 0; idx < count; ++idx) {
unsigned type = ELF32_R_TYPE(rel->r_info);
unsigned sym = ELF32_R_SYM(rel->r_info);
- unsigned reloc = (unsigned)(rel->r_offset + si->base);
+ unsigned reloc = (unsigned)(rel->r_offset + si->base - si->load_offset);
unsigned sym_addr = 0;
char *sym_name = NULL;
@@ -1296,7 +1331,7 @@
si->name, idx);
if(sym != 0) {
sym_name = (char *)(strtab + symtab[sym].st_name);
- s = _do_lookup(si, sym_name, &base);
+ s = _do_lookup(si, sym_name, &base, &offset);
if(s == NULL) {
/* We only allow an undefined symbol if this is a weak
reference.. */
@@ -1363,7 +1398,7 @@
return -1;
}
#endif
- sym_addr = (unsigned)(s->st_value + base);
+ sym_addr = (unsigned)(s->st_value + base - offset);
}
COUNT_RELOC(RELOC_SYMBOL);
} else {
@@ -1668,6 +1703,8 @@
static int link_image(soinfo *si, unsigned wr_offset)
{
unsigned *d;
+ /* "base" might wrap around UINT32_MAX. */
+ Elf32_Addr base = si->base - si->load_offset;
Elf32_Phdr *phdr = si->phdr;
int phnum = si->phnum;
@@ -1703,7 +1740,7 @@
We use the range [si->base, si->base + si->size) to
determine whether a PC value falls within the executable
section. Of course, if a value is between si->base and
- (si->base + phdr->p_vaddr), it's not in the executable
+ (base + phdr->p_vaddr), it's not in the executable
section, but a) we shouldn't be asking for such a value
anyway, and b) if we have to provide an EXIDX for such a
value, then the executable's EXIDX is probably the better
@@ -1717,9 +1754,9 @@
if (!(phdr->p_flags & PF_W)) {
unsigned _end;
- if (si->base + phdr->p_vaddr < si->wrprotect_start)
- si->wrprotect_start = si->base + phdr->p_vaddr;
- _end = (((si->base + phdr->p_vaddr + phdr->p_memsz + PAGE_SIZE - 1) &
+ if (base + phdr->p_vaddr < si->wrprotect_start)
+ si->wrprotect_start = base + phdr->p_vaddr;
+ _end = (((base + phdr->p_vaddr + phdr->p_memsz + PAGE_SIZE - 1) &
(~PAGE_MASK)));
if (_end > si->wrprotect_end)
si->wrprotect_end = _end;
@@ -1728,7 +1765,7 @@
* However, we will remember what range of addresses
* should be write protected.
*/
- mprotect((void *) (si->base + phdr->p_vaddr),
+ mprotect((void *) (base + phdr->p_vaddr),
phdr->p_memsz,
PFLAGS_TO_PROT(phdr->p_flags) | PROT_WRITE);
}
@@ -1736,22 +1773,22 @@
if (si->dynamic != (unsigned *)-1) {
DL_ERR("%5d multiple PT_DYNAMIC segments found in '%s'. "
"Segment at 0x%08x, previously one found at 0x%08x",
- pid, si->name, si->base + phdr->p_vaddr,
+ pid, si->name, base + phdr->p_vaddr,
(unsigned)si->dynamic);
goto fail;
}
DEBUG_DUMP_PHDR(phdr, "PT_DYNAMIC", pid);
- si->dynamic = (unsigned *) (si->base + phdr->p_vaddr);
+ si->dynamic = (unsigned *) (base + phdr->p_vaddr);
} else if (phdr->p_type == PT_GNU_RELRO) {
- if ((phdr->p_vaddr >= si->size)
- || ((phdr->p_vaddr + phdr->p_memsz) > si->size)
- || ((si->base + phdr->p_vaddr + phdr->p_memsz) < si->base)) {
+ if ((base + phdr->p_vaddr >= si->base + si->size)
+ || ((base + phdr->p_vaddr + phdr->p_memsz) > si->base + si->size)
+ || ((base + phdr->p_vaddr + phdr->p_memsz) < si->base)) {
DL_ERR("%d invalid GNU_RELRO in '%s' "
"p_vaddr=0x%08x p_memsz=0x%08x", pid, si->name,
phdr->p_vaddr, phdr->p_memsz);
goto fail;
}
- si->gnu_relro_start = (Elf32_Addr) (si->base + phdr->p_vaddr);
+ si->gnu_relro_start = (Elf32_Addr) (base + phdr->p_vaddr);
si->gnu_relro_len = (unsigned) phdr->p_memsz;
}
}
@@ -1769,16 +1806,16 @@
DEBUG("%5d d = %p, d[0] = 0x%08x d[1] = 0x%08x\n", pid, d, d[0], d[1]);
switch(*d++){
case DT_HASH:
- si->nbucket = ((unsigned *) (si->base + *d))[0];
- si->nchain = ((unsigned *) (si->base + *d))[1];
- si->bucket = (unsigned *) (si->base + *d + 8);
- si->chain = (unsigned *) (si->base + *d + 8 + si->nbucket * 4);
+ si->nbucket = ((unsigned *) (base + *d))[0];
+ si->nchain = ((unsigned *) (base + *d))[1];
+ si->bucket = (unsigned *) (base + *d + 8);
+ si->chain = (unsigned *) (base + *d + 8 + si->nbucket * 4);
break;
case DT_STRTAB:
- si->strtab = (const char *) (si->base + *d);
+ si->strtab = (const char *) (base + *d);
break;
case DT_SYMTAB:
- si->symtab = (Elf32_Sym *) (si->base + *d);
+ si->symtab = (Elf32_Sym *) (base + *d);
break;
case DT_PLTREL:
if(*d != DT_REL) {
@@ -1787,20 +1824,20 @@
}
break;
case DT_JMPREL:
- si->plt_rel = (Elf32_Rel*) (si->base + *d);
+ si->plt_rel = (Elf32_Rel*) (base + *d);
break;
case DT_PLTRELSZ:
si->plt_rel_count = *d / 8;
break;
case DT_REL:
- si->rel = (Elf32_Rel*) (si->base + *d);
+ si->rel = (Elf32_Rel*) (base + *d);
break;
case DT_RELSZ:
si->rel_count = *d / 8;
break;
case DT_PLTGOT:
/* Save this in case we decide to do lazy binding. We don't yet. */
- si->plt_got = (unsigned *)(si->base + *d);
+ si->plt_got = (unsigned *)(base + *d);
break;
case DT_DEBUG:
// Set the DT_DEBUG entry to the addres of _r_debug for GDB
@@ -1810,17 +1847,17 @@
DL_ERR("%5d DT_RELA not supported", pid);
goto fail;
case DT_INIT:
- si->init_func = (void (*)(void))(si->base + *d);
+ si->init_func = (void (*)(void))(base + *d);
DEBUG("%5d %s constructors (init func) found at %p\n",
pid, si->name, si->init_func);
break;
case DT_FINI:
- si->fini_func = (void (*)(void))(si->base + *d);
+ si->fini_func = (void (*)(void))(base + *d);
DEBUG("%5d %s destructors (fini func) found at %p\n",
pid, si->name, si->fini_func);
break;
case DT_INIT_ARRAY:
- si->init_array = (unsigned *)(si->base + *d);
+ si->init_array = (unsigned *)(base + *d);
DEBUG("%5d %s constructors (init_array) found at %p\n",
pid, si->name, si->init_array);
break;
@@ -1828,7 +1865,7 @@
si->init_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
break;
case DT_FINI_ARRAY:
- si->fini_array = (unsigned *)(si->base + *d);
+ si->fini_array = (unsigned *)(base + *d);
DEBUG("%5d %s destructors (fini_array) found at %p\n",
pid, si->name, si->fini_array);
break;
@@ -1836,7 +1873,7 @@
si->fini_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
break;
case DT_PREINIT_ARRAY:
- si->preinit_array = (unsigned *)(si->base + *d);
+ si->preinit_array = (unsigned *)(base + *d);
DEBUG("%5d %s constructors (preinit_array) found at %p\n",
pid, si->name, si->preinit_array);
break;
@@ -2150,6 +2187,7 @@
break;
}
}
+ si->load_offset = 0;
si->dynamic = (unsigned *)-1;
si->wrprotect_start = 0xffffffff;
si->wrprotect_end = 0;
@@ -2267,6 +2305,7 @@
memset(&linker_so, 0, sizeof(soinfo));
linker_so.base = linker_addr;
+ linker_so.load_offset = 0;
linker_so.dynamic = (unsigned *) -1;
linker_so.phdr = phdr;
linker_so.phnum = elf_hdr->e_phnum;
diff --git a/linker/linker.h b/linker/linker.h
index 0c986cd..c6b81ea 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -148,6 +148,10 @@
Elf32_Addr gnu_relro_start;
unsigned gnu_relro_len;
+ /* When you read a virtual address from the ELF file, add the load
+ * address (= "base" field) minus this value (= "load_offset") to get the
+ * real, corresponding address in the process' address space */
+ Elf32_Addr load_offset;
};