* commit '82b69fcbb3cc94bcde82c72d5c66fb3b504cdb6e': linker: avoid clobbering the .dynamic section of shared libs
This commit is contained in:
commit
dc320d99f1
@ -93,12 +93,6 @@ static soinfo *somain; /* main process, always the one after libdl_info */
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static inline int validate_soinfo(soinfo *si)
|
|
||||||
{
|
|
||||||
return (si >= sopool && si < sopool + SO_MAX) ||
|
|
||||||
si == &libdl_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char ldpaths_buf[LDPATH_BUFSIZE];
|
static char ldpaths_buf[LDPATH_BUFSIZE];
|
||||||
static const char *ldpaths[LDPATH_MAX + 1];
|
static const char *ldpaths[LDPATH_MAX + 1];
|
||||||
|
|
||||||
@ -427,11 +421,11 @@ static unsigned elfhash(const char *_name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Elf32_Sym *
|
static Elf32_Sym *
|
||||||
soinfo_do_lookup(soinfo *si, const char *name, Elf32_Addr *offset)
|
soinfo_do_lookup(soinfo *si, const char *name, Elf32_Addr *offset,
|
||||||
|
soinfo *needed[])
|
||||||
{
|
{
|
||||||
unsigned elf_hash = elfhash(name);
|
unsigned elf_hash = elfhash(name);
|
||||||
Elf32_Sym *s;
|
Elf32_Sym *s;
|
||||||
unsigned *d;
|
|
||||||
soinfo *lsi = si;
|
soinfo *lsi = si;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -457,21 +451,14 @@ soinfo_do_lookup(soinfo *si, const char *name, Elf32_Addr *offset)
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(d = si->dynamic; *d; d += 2) {
|
for(i = 0; needed[i] != NULL; i++) {
|
||||||
if(d[0] == DT_NEEDED){
|
lsi = needed[i];
|
||||||
lsi = (soinfo *)d[1];
|
|
||||||
if (!validate_soinfo(lsi)) {
|
|
||||||
DL_ERR("bad DT_NEEDED pointer in \"%s\"", lsi->name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG("%5d %s: looking up %s in %s\n",
|
DEBUG("%5d %s: looking up %s in %s\n",
|
||||||
pid, si->name, name, lsi->name);
|
pid, si->name, name, lsi->name);
|
||||||
s = soinfo_elf_lookup(lsi, elf_hash, name);
|
s = soinfo_elf_lookup(lsi, elf_hash, name);
|
||||||
if (s != NULL)
|
if (s != NULL)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#if ALLOW_SYMBOLS_FROM_MAIN
|
#if ALLOW_SYMBOLS_FROM_MAIN
|
||||||
/* If we are resolving relocations while dlopen()ing a library, it's OK for
|
/* If we are resolving relocations while dlopen()ing a library, it's OK for
|
||||||
@ -857,11 +844,29 @@ init_library(soinfo *si)
|
|||||||
return si;
|
return si;
|
||||||
}
|
}
|
||||||
|
|
||||||
soinfo *find_library(const char *name)
|
static soinfo *find_loaded_library(const char *name)
|
||||||
{
|
{
|
||||||
soinfo *si;
|
soinfo *si;
|
||||||
const char *bname;
|
const char *bname;
|
||||||
|
|
||||||
|
// TODO: don't use basename only for determining libraries
|
||||||
|
// http://code.google.com/p/android/issues/detail?id=6670
|
||||||
|
|
||||||
|
bname = strrchr(name, '/');
|
||||||
|
bname = bname ? bname + 1 : name;
|
||||||
|
|
||||||
|
for(si = solist; si != NULL; si = si->next){
|
||||||
|
if(!strcmp(bname, si->name)) {
|
||||||
|
return si;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
soinfo *find_library(const char *name)
|
||||||
|
{
|
||||||
|
soinfo *si;
|
||||||
|
|
||||||
#if ALLOW_SYMBOLS_FROM_MAIN
|
#if ALLOW_SYMBOLS_FROM_MAIN
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
return somain;
|
return somain;
|
||||||
@ -870,20 +875,16 @@ soinfo *find_library(const char *name)
|
|||||||
return NULL;
|
return NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bname = strrchr(name, '/');
|
si = find_loaded_library(name);
|
||||||
bname = bname ? bname + 1 : name;
|
if (si != NULL) {
|
||||||
|
|
||||||
for(si = solist; si != 0; si = si->next){
|
|
||||||
if(!strcmp(bname, si->name)) {
|
|
||||||
if(si->flags & FLAG_ERROR) {
|
if(si->flags & FLAG_ERROR) {
|
||||||
DL_ERR("\"%s\" failed to load previously", bname);
|
DL_ERR("\"%s\" failed to load previously", name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if(si->flags & FLAG_LINKED) return si;
|
if(si->flags & FLAG_LINKED) return si;
|
||||||
DL_ERR("OOPS: recursive link to \"%s\"", si->name);
|
DL_ERR("OOPS: recursive link to \"%s\"", si->name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TRACE("[ %5d '%s' has not been loaded yet. Locating...]\n", pid, name);
|
TRACE("[ %5d '%s' has not been loaded yet. Locating...]\n", pid, name);
|
||||||
si = load_library(name);
|
si = load_library(name);
|
||||||
@ -903,27 +904,11 @@ unsigned soinfo_unload(soinfo *si)
|
|||||||
TRACE("%5d unloading '%s'\n", pid, si->name);
|
TRACE("%5d unloading '%s'\n", pid, si->name);
|
||||||
call_destructors(si);
|
call_destructors(si);
|
||||||
|
|
||||||
/*
|
|
||||||
* Make sure that we undo the PT_GNU_RELRO protections we added
|
|
||||||
* in soinfo_link_image. This is needed to undo the DT_NEEDED hack below.
|
|
||||||
*/
|
|
||||||
if (phdr_table_unprotect_gnu_relro(si->phdr, si->phnum,
|
|
||||||
si->load_bias) < 0) {
|
|
||||||
DL_ERR("%s: could not undo GNU_RELRO protections. "
|
|
||||||
"Expect a crash soon. errno=%d (%s)",
|
|
||||||
si->name, errno, strerror(errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
for(d = si->dynamic; *d; d += 2) {
|
for(d = si->dynamic; *d; d += 2) {
|
||||||
if(d[0] == DT_NEEDED){
|
if(d[0] == DT_NEEDED){
|
||||||
soinfo *lsi = (soinfo *)d[1];
|
soinfo *lsi = find_loaded_library(si->strtab + d[1]);
|
||||||
|
|
||||||
// The next line will segfault if the we don't undo the
|
if (lsi) {
|
||||||
// PT_GNU_RELRO protections (see comments above and in
|
|
||||||
// soinfo_link_image().
|
|
||||||
d[1] = 0;
|
|
||||||
|
|
||||||
if (validate_soinfo(lsi)) {
|
|
||||||
TRACE("%5d %s needs to unload %s\n", pid,
|
TRACE("%5d %s needs to unload %s\n", pid,
|
||||||
si->name, lsi->name);
|
si->name, lsi->name);
|
||||||
soinfo_unload(lsi);
|
soinfo_unload(lsi);
|
||||||
@ -951,7 +936,8 @@ unsigned soinfo_unload(soinfo *si)
|
|||||||
* ideal. They should probably be either uint32_t, Elf32_Addr, or unsigned
|
* ideal. They should probably be either uint32_t, Elf32_Addr, or unsigned
|
||||||
* long.
|
* long.
|
||||||
*/
|
*/
|
||||||
static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count)
|
static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count,
|
||||||
|
soinfo *needed[])
|
||||||
{
|
{
|
||||||
Elf32_Sym *symtab = si->symtab;
|
Elf32_Sym *symtab = si->symtab;
|
||||||
const char *strtab = si->strtab;
|
const char *strtab = si->strtab;
|
||||||
@ -973,7 +959,7 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count)
|
|||||||
}
|
}
|
||||||
if(sym != 0) {
|
if(sym != 0) {
|
||||||
sym_name = (char *)(strtab + symtab[sym].st_name);
|
sym_name = (char *)(strtab + symtab[sym].st_name);
|
||||||
s = soinfo_do_lookup(si, sym_name, &offset);
|
s = soinfo_do_lookup(si, sym_name, &offset, needed);
|
||||||
if(s == NULL) {
|
if(s == NULL) {
|
||||||
/* We only allow an undefined symbol if this is a weak
|
/* We only allow an undefined symbol if this is a weak
|
||||||
reference.. */
|
reference.. */
|
||||||
@ -1171,7 +1157,7 @@ static int soinfo_relocate(soinfo *si, Elf32_Rel *rel, unsigned count)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ANDROID_MIPS_LINKER
|
#ifdef ANDROID_MIPS_LINKER
|
||||||
int mips_relocate_got(struct soinfo *si)
|
int mips_relocate_got(struct soinfo *si, soinfo *needed[])
|
||||||
{
|
{
|
||||||
unsigned *got;
|
unsigned *got;
|
||||||
unsigned local_gotno, gotsym, symtabno;
|
unsigned local_gotno, gotsym, symtabno;
|
||||||
@ -1216,7 +1202,7 @@ int mips_relocate_got(struct soinfo *si)
|
|||||||
|
|
||||||
/* This is an undefined reference... try to locate it */
|
/* This is an undefined reference... try to locate it */
|
||||||
sym_name = si->strtab + sym->st_name;
|
sym_name = si->strtab + sym->st_name;
|
||||||
s = soinfo_do_lookup(si, sym_name, &base);
|
s = soinfo_do_lookup(si, sym_name, &base, needed);
|
||||||
if (s == NULL) {
|
if (s == NULL) {
|
||||||
/* We only allow an undefined symbol if this is a weak
|
/* We only allow an undefined symbol if this is a weak
|
||||||
reference.. */
|
reference.. */
|
||||||
@ -1312,9 +1298,10 @@ void soinfo_call_constructors(soinfo *si)
|
|||||||
unsigned *d;
|
unsigned *d;
|
||||||
for(d = si->dynamic; *d; d += 2) {
|
for(d = si->dynamic; *d; d += 2) {
|
||||||
if(d[0] == DT_NEEDED){
|
if(d[0] == DT_NEEDED){
|
||||||
soinfo* lsi = (soinfo *)d[1];
|
soinfo* lsi = find_loaded_library(si->strtab + d[1]);
|
||||||
if (!validate_soinfo(lsi)) {
|
if (!lsi) {
|
||||||
DL_ERR("bad DT_NEEDED pointer in \"%s\"", si->name);
|
DL_ERR("\"%s\": could not initialize dependent library",
|
||||||
|
si->name);
|
||||||
} else {
|
} else {
|
||||||
soinfo_call_constructors(lsi);
|
soinfo_call_constructors(lsi);
|
||||||
}
|
}
|
||||||
@ -1425,6 +1412,8 @@ static int soinfo_link_image(soinfo *si)
|
|||||||
const Elf32_Phdr *phdr = si->phdr;
|
const Elf32_Phdr *phdr = si->phdr;
|
||||||
int phnum = si->phnum;
|
int phnum = si->phnum;
|
||||||
int relocating_linker = (si->flags & FLAG_LINKER) != 0;
|
int relocating_linker = (si->flags & FLAG_LINKER) != 0;
|
||||||
|
soinfo **needed, **pneeded;
|
||||||
|
size_t dynamic_count;
|
||||||
|
|
||||||
/* We can't debug anything until the linker is relocated */
|
/* We can't debug anything until the linker is relocated */
|
||||||
if (!relocating_linker) {
|
if (!relocating_linker) {
|
||||||
@ -1434,7 +1423,8 @@ static int soinfo_link_image(soinfo *si)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Extract dynamic section */
|
/* Extract dynamic section */
|
||||||
si->dynamic = phdr_table_get_dynamic_section(phdr, phnum, base);
|
phdr_table_get_dynamic_section(phdr, phnum, base, &si->dynamic,
|
||||||
|
&dynamic_count);
|
||||||
if (si->dynamic == NULL) {
|
if (si->dynamic == NULL) {
|
||||||
if (!relocating_linker) {
|
if (!relocating_linker) {
|
||||||
DL_ERR("missing PT_DYNAMIC?!");
|
DL_ERR("missing PT_DYNAMIC?!");
|
||||||
@ -1607,6 +1597,9 @@ static int soinfo_link_image(soinfo *si)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* dynamic_count is an upper bound for the number of needed libs */
|
||||||
|
pneeded = needed = (soinfo**) alloca((1 + dynamic_count) * sizeof(soinfo*));
|
||||||
|
|
||||||
for(d = si->dynamic; *d; d += 2) {
|
for(d = si->dynamic; *d; d += 2) {
|
||||||
if(d[0] == DT_NEEDED){
|
if(d[0] == DT_NEEDED){
|
||||||
DEBUG("%5d %s needs %s\n", pid, si->name, si->strtab + d[1]);
|
DEBUG("%5d %s needs %s\n", pid, si->name, si->strtab + d[1]);
|
||||||
@ -1617,17 +1610,11 @@ static int soinfo_link_image(soinfo *si)
|
|||||||
si->strtab + d[1], si->name, tmp_err_buf);
|
si->strtab + d[1], si->name, tmp_err_buf);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
/* Save the soinfo of the loaded DT_NEEDED library in the payload
|
*pneeded++ = lsi;
|
||||||
of the DT_NEEDED entry itself, so that we can retrieve the
|
|
||||||
soinfo directly later from the dynamic segment. This is a hack,
|
|
||||||
but it allows us to map from DT_NEEDED to soinfo efficiently
|
|
||||||
later on when we resolve relocations, trying to look up a symbol
|
|
||||||
with dlsym().
|
|
||||||
*/
|
|
||||||
d[1] = (unsigned)lsi;
|
|
||||||
lsi->refcount++;
|
lsi->refcount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*pneeded = NULL;
|
||||||
|
|
||||||
if (si->has_text_relocations) {
|
if (si->has_text_relocations) {
|
||||||
/* Unprotect the segments, i.e. make them writable, to allow
|
/* Unprotect the segments, i.e. make them writable, to allow
|
||||||
@ -1644,17 +1631,17 @@ static int soinfo_link_image(soinfo *si)
|
|||||||
|
|
||||||
if(si->plt_rel) {
|
if(si->plt_rel) {
|
||||||
DEBUG("[ %5d relocating %s plt ]\n", pid, si->name );
|
DEBUG("[ %5d relocating %s plt ]\n", pid, si->name );
|
||||||
if(soinfo_relocate(si, si->plt_rel, si->plt_rel_count))
|
if(soinfo_relocate(si, si->plt_rel, si->plt_rel_count, needed))
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if(si->rel) {
|
if(si->rel) {
|
||||||
DEBUG("[ %5d relocating %s ]\n", pid, si->name );
|
DEBUG("[ %5d relocating %s ]\n", pid, si->name );
|
||||||
if(soinfo_relocate(si, si->rel, si->rel_count))
|
if(soinfo_relocate(si, si->rel, si->rel_count, needed))
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ANDROID_MIPS_LINKER
|
#ifdef ANDROID_MIPS_LINKER
|
||||||
if(mips_relocate_got(si)) {
|
if(mips_relocate_got(si, needed)) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -1849,8 +1836,8 @@ sanitize:
|
|||||||
Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *) linker_base;
|
Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *) linker_base;
|
||||||
Elf32_Phdr *phdr =
|
Elf32_Phdr *phdr =
|
||||||
(Elf32_Phdr *)((unsigned char *) linker_base + elf_hdr->e_phoff);
|
(Elf32_Phdr *)((unsigned char *) linker_base + elf_hdr->e_phoff);
|
||||||
linker_soinfo.dynamic =
|
phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base,
|
||||||
phdr_table_get_dynamic_section(phdr, elf_hdr->e_phnum, linker_base);
|
&linker_soinfo.dynamic, NULL);
|
||||||
insert_soinfo_into_debug_map(&linker_soinfo);
|
insert_soinfo_into_debug_map(&linker_soinfo);
|
||||||
|
|
||||||
/* extract information passed from the kernel */
|
/* extract information passed from the kernel */
|
||||||
|
@ -468,11 +468,9 @@ _phdr_table_set_gnu_relro_prot(const Elf32_Phdr* phdr_table,
|
|||||||
* specified by one or more PT_GNU_RELRO segments. This must be always
|
* specified by one or more PT_GNU_RELRO segments. This must be always
|
||||||
* performed after relocations.
|
* performed after relocations.
|
||||||
*
|
*
|
||||||
* NOTE: One must call phdr_table_unprotect_gnu_relro() before calling
|
* The areas typically covered are .got and .data.rel.ro, these are
|
||||||
* the library's destructors, in order to ensure that the .dynamic
|
* read-only from the program's POV, but contain absolute addresses
|
||||||
* section is writable (as well as the .data.relro section that
|
* that need to be relocated before use.
|
||||||
* might contain the content of static constant C++ objects that
|
|
||||||
* needs to be destroyed).
|
|
||||||
*
|
*
|
||||||
* Input:
|
* Input:
|
||||||
* phdr_table -> program header table
|
* phdr_table -> program header table
|
||||||
@ -492,27 +490,6 @@ phdr_table_protect_gnu_relro(const Elf32_Phdr* phdr_table,
|
|||||||
PROT_READ);
|
PROT_READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Un-apply GNU relro protection if specified by the program header.
|
|
||||||
* See comment for phdr_table_protect_gnu_relro.
|
|
||||||
*
|
|
||||||
* Input:
|
|
||||||
* phdr_table -> program header table
|
|
||||||
* phdr_count -> number of entires in tables
|
|
||||||
* load_bias -> load bias
|
|
||||||
* Return:
|
|
||||||
* 0 on error, -1 on failure (error code in errno).
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
phdr_table_unprotect_gnu_relro(const Elf32_Phdr* phdr_table,
|
|
||||||
int phdr_count,
|
|
||||||
Elf32_Addr load_bias)
|
|
||||||
{
|
|
||||||
return _phdr_table_set_gnu_relro_prot(phdr_table,
|
|
||||||
phdr_count,
|
|
||||||
load_bias,
|
|
||||||
PROT_READ|PROT_WRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ANDROID_ARM_LINKER
|
#ifdef ANDROID_ARM_LINKER
|
||||||
|
|
||||||
# ifndef PT_ARM_EXIDX
|
# ifndef PT_ARM_EXIDX
|
||||||
@ -556,30 +533,44 @@ phdr_table_get_arm_exidx(const Elf32_Phdr* phdr_table,
|
|||||||
}
|
}
|
||||||
#endif /* ANDROID_ARM_LINKER */
|
#endif /* ANDROID_ARM_LINKER */
|
||||||
|
|
||||||
/* Return the address of the ELF file's .dynamic section in memory,
|
/* Return the address and size of the ELF file's .dynamic section in memory,
|
||||||
* or NULL if missing.
|
* or NULL if missing.
|
||||||
*
|
*
|
||||||
* Input:
|
* Input:
|
||||||
* phdr_table -> program header table
|
* phdr_table -> program header table
|
||||||
* phdr_count -> number of entires in tables
|
* phdr_count -> number of entires in tables
|
||||||
* load_bias -> load bias
|
* load_bias -> load bias
|
||||||
|
* Output:
|
||||||
|
* dynamic -> address of table in memory (NULL on failure).
|
||||||
|
* dynamic_count -> number of items in table (0 on failure).
|
||||||
* Return:
|
* Return:
|
||||||
* 0 on error, -1 on failure (_no_ error code in errno)
|
* void
|
||||||
*/
|
*/
|
||||||
Elf32_Addr*
|
void
|
||||||
phdr_table_get_dynamic_section(const Elf32_Phdr* phdr_table,
|
phdr_table_get_dynamic_section(const Elf32_Phdr* phdr_table,
|
||||||
int phdr_count,
|
int phdr_count,
|
||||||
Elf32_Addr load_bias)
|
Elf32_Addr load_bias,
|
||||||
|
Elf32_Addr** dynamic,
|
||||||
|
size_t* dynamic_count)
|
||||||
{
|
{
|
||||||
const Elf32_Phdr* phdr = phdr_table;
|
const Elf32_Phdr* phdr = phdr_table;
|
||||||
const Elf32_Phdr* phdr_limit = phdr + phdr_count;
|
const Elf32_Phdr* phdr_limit = phdr + phdr_count;
|
||||||
|
|
||||||
for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
|
for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
|
||||||
if (phdr->p_type == PT_DYNAMIC) {
|
if (phdr->p_type != PT_DYNAMIC) {
|
||||||
return (Elf32_Addr*)(load_bias + phdr->p_vaddr);
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*dynamic = (Elf32_Addr*)(load_bias + phdr->p_vaddr);
|
||||||
|
if (dynamic_count) {
|
||||||
|
*dynamic_count = (unsigned)(phdr->p_memsz / 8);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*dynamic = NULL;
|
||||||
|
if (dynamic_count) {
|
||||||
|
*dynamic_count = 0;
|
||||||
}
|
}
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the address of the program header table as it appears in the loaded
|
/* Return the address of the program header table as it appears in the loaded
|
||||||
|
@ -86,11 +86,6 @@ phdr_table_protect_gnu_relro(const Elf32_Phdr* phdr_table,
|
|||||||
int phdr_count,
|
int phdr_count,
|
||||||
Elf32_Addr load_bias);
|
Elf32_Addr load_bias);
|
||||||
|
|
||||||
int
|
|
||||||
phdr_table_unprotect_gnu_relro(const Elf32_Phdr* phdr_table,
|
|
||||||
int phdr_count,
|
|
||||||
Elf32_Addr load_bias);
|
|
||||||
|
|
||||||
const Elf32_Phdr*
|
const Elf32_Phdr*
|
||||||
phdr_table_get_loaded_phdr(const Elf32_Phdr* phdr_table,
|
phdr_table_get_loaded_phdr(const Elf32_Phdr* phdr_table,
|
||||||
int phdr_count,
|
int phdr_count,
|
||||||
@ -105,10 +100,12 @@ phdr_table_get_arm_exidx(const Elf32_Phdr* phdr_table,
|
|||||||
unsigned* arm_exidix_count);
|
unsigned* arm_exidix_count);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Elf32_Addr*
|
void
|
||||||
phdr_table_get_dynamic_section(const Elf32_Phdr* phdr_table,
|
phdr_table_get_dynamic_section(const Elf32_Phdr* phdr_table,
|
||||||
int phdr_count,
|
int phdr_count,
|
||||||
Elf32_Addr load_bias);
|
Elf32_Addr load_bias,
|
||||||
|
Elf32_Addr** dynamic,
|
||||||
|
size_t* dynamic_count);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user