2000-02-12 Andreas Jaeger <aj@suse.de>

* sysdeps/mips/dl-machine.h (__start): Rewritten for 2.2 startup
	conventions.
	(elf_machine_rel): Use R_MIPS_REL32 for RESOLVE.
	(elf_machine_runtime_setup,elf_machine_got_rel): Move at end of
	file and make dependend on RESOLVE.
	(ELF_MACHINE_RUNTIME_TRAMPOLINE): Fix arguments to _dl_lookup_symbol.
	(RESOLVE_GOTSYM): Fix arguments to _dl_lookup_symbol.
This commit is contained in:
Andreas Jaeger 2000-02-12 11:27:47 +00:00
parent e1b4ab28ae
commit bab23124f0

View File

@ -59,8 +59,13 @@
/* /*
* MIPS libraries are usually linked to a non-zero base address. We * MIPS libraries are usually linked to a non-zero base address. We
* subtrace the base address from the address where we map the object * subtract the base address from the address where we map the object
* to. This results in more efficient address space usage. * to. This results in more efficient address space usage.
*
* FIXME: By the time when MAP_BASE_ADDR is called we don't have the
* DYNAMIC section read. Until this is fixed make the assumption that
* libraries have their base address at 0x5ffe0000. This needs to be
* fixed before we can safely get rid of this MIPSism.
*/ */
#if 0 #if 0
#define MAP_BASE_ADDR(l) ((l)->l_info[DT_MIPS(BASE_ADDRESS)] ? \ #define MAP_BASE_ADDR(l) ((l)->l_info[DT_MIPS(BASE_ADDRESS)] ? \
@ -126,125 +131,8 @@ elf_machine_load_address (void)
return addr; return addr;
} }
/* The MSB of got[1] of a gnu object is set to identify gnu objects. */
#define ELF_MIPS_GNU_GOT1_MASK 0x80000000
/* Relocate GOT. */ /* Get link map for callers object containing STUB_PC. */
static inline void
elf_machine_got_rel (struct link_map *map, int lazy)
{
ElfW(Addr) *got;
ElfW(Sym) *sym;
int i, n;
const char *strtab = (const void *) map->l_info[DT_STRTAB]->d_un.d_ptr;
#define RESOLVE_GOTSYM(sym) \
({ \
const ElfW(Sym) *ref = sym; \
ElfW(Addr) sym_loadaddr; \
sym_loadaddr = _dl_lookup_symbol (strtab + sym->st_name, &ref, \
map->l_scope, \
map->l_name, R_MIPS_REL32);\
(ref)? sym_loadaddr + ref->st_value: 0; \
})
got = (ElfW(Addr) *) map->l_info[DT_PLTGOT]->d_un.d_ptr;
/* got[0] is reserved. got[1] is also reserved for the dynamic object
generated by gnu ld. Skip these reserved entries from relocation. */
i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2: 1;
n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
/* Add the run-time display to all local got entries. */
while (i < n)
got[i++] += map->l_addr;
/* Handle global got entries. */
got += n;
sym = (void *) map->l_info[DT_SYMTAB]->d_un.d_ptr;
sym += map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
i = (map->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val
- map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val);
while (i--)
{
if (sym->st_shndx == SHN_UNDEF)
{
if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC)
{
if (sym->st_value && lazy)
*got = sym->st_value + map->l_addr;
else
*got = RESOLVE_GOTSYM (sym);
}
else /* if (*got == 0 || *got == QS) */
*got = RESOLVE_GOTSYM (sym);
}
else if (sym->st_shndx == SHN_COMMON)
*got = RESOLVE_GOTSYM (sym);
else if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC
&& *got != sym->st_value
&& lazy)
*got += map->l_addr;
else if (ELFW(ST_TYPE) (sym->st_info) == STT_SECTION)
{
if (sym->st_other == 0)
*got += map->l_addr;
}
else
*got = RESOLVE_GOTSYM (sym);
got++;
sym++;
}
#undef RESOLVE_GOTSYM
return;
}
/* Set up the loaded object described by L so its stub function
will jump to the on-demand fixup code in dl-runtime.c. */
static inline int
elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
{
ElfW(Addr) *got;
extern void _dl_runtime_resolve (ElfW(Word));
extern int _dl_mips_gnu_objects;
#ifdef RTLD_BOOTSTRAP
{
return lazy;
}
#endif
if (lazy)
{
/* The GOT entries for functions have not yet been filled in.
Their initial contents will arrange when called to put an
offset into the .dynsym section in t8, the return address
in t7 and then jump to _GLOBAL_OFFSET_TABLE[0]. */
got = (ElfW(Addr) *) l->l_info[DT_PLTGOT]->d_un.d_ptr;
/* This function will get called to fix up the GOT entry indicated by
the register t8, and then jump to the resolved address. */
got[0] = (ElfW(Addr)) &_dl_runtime_resolve;
/* Store l to _GLOBAL_OFFSET_TABLE[1] for gnu object. The MSB
of got[1] of a gnu object is set to identify gnu objects.
Where we can store l for non gnu objects? XXX */
if ((got[1] & ELF_MIPS_GNU_GOT1_MASK) != 0)
got[1] = (ElfW(Addr)) ((unsigned) l | ELF_MIPS_GNU_GOT1_MASK);
else
_dl_mips_gnu_objects = 0;
}
/* Relocate global offset table. */
elf_machine_got_rel (l, lazy);
return lazy;
}
/* Get link_map for this object. */
static inline struct link_map * static inline struct link_map *
elf_machine_runtime_link_map (ElfW(Addr) gpreg, ElfW(Addr) stub_pc) elf_machine_runtime_link_map (ElfW(Addr) gpreg, ElfW(Addr) stub_pc)
{ {
@ -352,9 +240,8 @@ __dl_runtime_resolve (ElfW(Word) sym_index, \
/* Look up the symbol's run-time value. */ \ /* Look up the symbol's run-time value. */ \
definer = &symtab[sym_index]; \ definer = &symtab[sym_index]; \
\ \
loadbase = _dl_lookup_symbol (strtab + definer->st_name, &definer, \ loadbase = _dl_lookup_symbol (strtab + definer->st_name, l, &definer, \
l->l_scope, l->l_name, \ l->l_scope, R_MIPS_REL32); \
R_MIPS_REL32); \
\ \
/* Apply the relocation with that value. */ \ /* Apply the relocation with that value. */ \
funcaddr = loadbase + definer->st_value; \ funcaddr = loadbase + definer->st_value; \
@ -470,19 +357,33 @@ _dl_start_user:\n\
addu $29, $2\n\ addu $29, $2\n\
# Save back the modified argument count.\n\ # Save back the modified argument count.\n\
sw $4, 0($29)\n\ sw $4, 0($29)\n\
# Get _dl_default_scope[2] as argument in _dl_init_next call below.\n\ 1: subu $29, 16\n\
1: la $2, _dl_default_scope\n\ 2: # Push the searchlist of the main object as argument in\n\
lw $4, 8($2)\n\ # the _dl_preinit_next and _dl_init_next calls below.\n\
lw $4, _dl_main_searchlist\n\
# First run the pre-initializers.\n\
# Call _dl_preinit_next to return the address of an initializer\n\
# function to run.\n\
jal _dl_preinit_next
move $28, $16\n\
# Check for zero return, when out of initializers.\n\
beq $2, $0, 4f\n\
# Call the pre-initializer.\n\
move $25, $2\n\
jalr $25\n\
move $28, $16\n
# Loop to call _dl_preinit_next for the next initializer.\n\
b 2b\n
4: lw $4, _dl_main_searchlist\n\
# Call _dl_init_next to return the address of an initializer\n\ # Call _dl_init_next to return the address of an initializer\n\
# function to run.\n\ # function to run.\n\
subu $29, 16\n\
jal _dl_init_next\n\ jal _dl_init_next\n\
addiu $29, 16\n\
move $28, $16\n\ move $28, $16\n\
# Check for zero return, when out of initializers.\n\ # Check for zero return, when out of initializers.\n\
beq $2, $0, 2f\n\ beq $2, $0, 2f\n\
# Call the shared object initializer function.\n\ # Call the shared object initializer function.\n\
move $25, $2\n\ move $25, $2\n\
# XXX This looks broken ###.\n\
lw $4, 0($29)\n\ lw $4, 0($29)\n\
lw $5, 4($29)\n\ lw $5, 4($29)\n\
lw $6, 8($29)\n\ lw $6, 8($29)\n\
@ -490,8 +391,9 @@ _dl_start_user:\n\
jalr $25\n\ jalr $25\n\
move $28, $16\n\ move $28, $16\n\
# Loop to call _dl_init_next for the next initializer.\n\ # Loop to call _dl_init_next for the next initializer.\n\
b 1b\n\ b 4b\n\
2: # Clear the startup flag. Assumes 32 bit ints.\n\ 2: addiu $29, 16\n\
# Clear the startup flag. Assumes 32 bit ints.\n\
sw $0, _dl_starting_up\n\ sw $0, _dl_starting_up\n\
# Pass our finalizer function to the user in ra.\n\ # Pass our finalizer function to the user in ra.\n\
la $31, _dl_fini\n\ la $31, _dl_fini\n\
@ -552,7 +454,7 @@ elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc,
built-in definitions used while loading those libraries. */ built-in definitions used while loading those libraries. */
undo = map->l_addr + sym->st_value; undo = map->l_addr + sym->st_value;
#endif #endif
loadbase = RESOLVE (&sym, version, 0); loadbase = RESOLVE (&sym, version, R_MIPS_REL32);
*reloc_addr += (sym ? (loadbase + sym->st_value) : 0) - undo; *reloc_addr += (sym ? (loadbase + sym->st_value) : 0) - undo;
} }
break; break;
@ -571,4 +473,119 @@ elf_machine_lazy_rel (struct link_map *map,
/* Do nothing. */ /* Do nothing. */
} }
/* The MSB of got[1] of a gnu object is set to identify gnu objects. */
#define ELF_MIPS_GNU_GOT1_MASK 0x80000000
/* Relocate GOT. */
static inline void
elf_machine_got_rel (struct link_map *map, int lazy)
{
ElfW(Addr) *got;
ElfW(Sym) *sym;
int i, n;
const char *strtab = (const void *) map->l_info[DT_STRTAB]->d_un.d_ptr;
#define RESOLVE_GOTSYM(sym) \
({ \
const ElfW(Sym) *ref = sym; \
ElfW(Addr) sym_loadaddr; \
sym_loadaddr = _dl_lookup_symbol (strtab + sym->st_name, map, \
&ref, map->l_scope, \
R_MIPS_REL32); \
(ref)? sym_loadaddr + ref->st_value: 0; \
})
got = (ElfW(Addr) *) map->l_info[DT_PLTGOT]->d_un.d_ptr;
/* got[0] is reserved. got[1] is also reserved for the dynamic object
generated by gnu ld. Skip these reserved entries from relocation. */
i = (got[1] & ELF_MIPS_GNU_GOT1_MASK)? 2: 1;
n = map->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
/* Add the run-time display to all local got entries. */
while (i < n)
got[i++] += map->l_addr;
/* Handle global got entries. */
got += n;
sym = (void *) map->l_info[DT_SYMTAB]->d_un.d_ptr;
sym += map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
i = (map->l_info[DT_MIPS (SYMTABNO)]->d_un.d_val
- map->l_info[DT_MIPS (GOTSYM)]->d_un.d_val);
while (i--)
{
if (sym->st_shndx == SHN_UNDEF)
{
if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC)
{
if (sym->st_value && lazy)
*got = sym->st_value + map->l_addr;
else
*got = RESOLVE_GOTSYM (sym);
}
else /* if (*got == 0 || *got == QS) */
*got = RESOLVE_GOTSYM (sym);
}
else if (sym->st_shndx == SHN_COMMON)
*got = RESOLVE_GOTSYM (sym);
else if (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC
&& *got != sym->st_value
&& lazy)
*got += map->l_addr;
else if (ELFW(ST_TYPE) (sym->st_info) == STT_SECTION)
{
if (sym->st_other == 0)
*got += map->l_addr;
}
else
*got = RESOLVE_GOTSYM (sym);
got++;
sym++;
}
#undef RESOLVE_GOTSYM
return;
}
/* Set up the loaded object described by L so its stub function
will jump to the on-demand fixup code in dl-runtime.c. */
static inline int
elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
{
# ifndef RTLD_BOOTSTRAP
ElfW(Addr) *got;
extern void _dl_runtime_resolve (ElfW(Word));
extern int _dl_mips_gnu_objects;
if (lazy)
{
/* The GOT entries for functions have not yet been filled in.
Their initial contents will arrange when called to put an
offset into the .dynsym section in t8, the return address
in t7 and then jump to _GLOBAL_OFFSET_TABLE[0]. */
got = (ElfW(Addr) *) l->l_info[DT_PLTGOT]->d_un.d_ptr;
/* This function will get called to fix up the GOT entry indicated by
the register t8, and then jump to the resolved address. */
got[0] = (ElfW(Addr)) &_dl_runtime_resolve;
/* Store l to _GLOBAL_OFFSET_TABLE[1] for gnu object. The MSB
of got[1] of a gnu object is set to identify gnu objects.
Where we can store l for non gnu objects? XXX */
if ((got[1] & ELF_MIPS_GNU_GOT1_MASK) != 0)
got[1] = (ElfW(Addr)) ((unsigned) l | ELF_MIPS_GNU_GOT1_MASK);
else
_dl_mips_gnu_objects = 0;
}
/* Relocate global offset table. */
elf_machine_got_rel (l, lazy);
# endif
return lazy;
}
#endif /* RESOLVE */ #endif /* RESOLVE */