summaryrefslogtreecommitdiff
path: root/gnu/libexec/ld.so/ld.so/mips/elfinterp.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/libexec/ld.so/ld.so/mips/elfinterp.c')
-rw-r--r--gnu/libexec/ld.so/ld.so/mips/elfinterp.c451
1 files changed, 0 insertions, 451 deletions
diff --git a/gnu/libexec/ld.so/ld.so/mips/elfinterp.c b/gnu/libexec/ld.so/ld.so/mips/elfinterp.c
deleted file mode 100644
index 148010527a1..00000000000
--- a/gnu/libexec/ld.so/ld.so/mips/elfinterp.c
+++ /dev/null
@@ -1,451 +0,0 @@
-/* Run an ELF binary on a OpenBSD system.
-
- Copyright (C) 1993, Eric Youngdale.
- Copyright (C) 1995, Andreas Schwab.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-
-/* Program to load an ELF binary on a OpenBSD system, and run it.
- References to symbols in sharable libraries can be resolved by either
- an ELF sharable library or a linux style of shared library. */
-
-/* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
- I ever taken any courses on internals. This program was developed using
- information available through the book "UNIX SYSTEM V RELEASE 4,
- Programmers guide: Ansi C and Programming Support Tools", which did
- a more than adequate job of explaining everything required to get this
- working. */
-
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <elf.h>
-
-#include "hash.h"
-#include "syscall.h"
-#include "sysdep.h"
-#include "string.h"
-
-extern char *_dl_progname;
-
-/* Search loaded objects' symbol tables for a definition of
- the symbol UNDEF_NAME. If NOSELF is nonzero, then *REF
- cannot satisfy the reference itself; some different binding
- must be found. */
-
-Elf32_Addr
-_dl_lookup_symbol (const char *undef_name, const Elf32_Sym **ref,
- struct elf_resolve *symbol_scope,
- const char *reference_name,
- int noself)
-{
- unsigned long int hash = _dl_elf_hash (undef_name);
- struct elf_resolve *map;
- struct
- {
- Elf32_Addr a;
- const Elf32_Sym *s;
- } weak_value; /* = { 0, NULL }; breaks GCC 2.8 due to implicit memset */
-
- _dl_memset (&weak_value, 0, sizeof (weak_value));
-
- /* Search the relevant loaded objects for a definition. */
- for (map = symbol_scope; map; map = map->next)
- {
- const Elf32_Sym *symtab;
- const char *strtab;
- Elf32_Word symidx;
-
- symtab = ((void *) map->loadoffs + map->dynamic_info[DT_SYMTAB]);
- strtab = ((void *) map->loadoffs + map->dynamic_info[DT_STRTAB]);
-
- /* Search the appropriate hash bucket in this object's symbol table
- for a definition for the same symbol name. */
- for (symidx = map->elf_buckets[hash % map->nbucket];
- symidx != STN_UNDEF;
- symidx = map->chains[symidx])
- {
- const Elf32_Sym *sym = &symtab[symidx];
-
- if (sym->st_value == 0 || /* No value. */
- sym->st_shndx == SHN_UNDEF || /* PLT entry. */
- (noself && sym == *ref)) /* The reference can't define it. */
- continue;
-
- switch (ELF32_ST_TYPE (sym->st_info))
- {
- case STT_NOTYPE:
- case STT_FUNC:
- case STT_OBJECT:
- break;
- default:
- /* Not a code/data definition. */
- continue;
- }
-
- if (sym != *ref && _dl_strcmp (strtab + sym->st_name, undef_name))
- /* Not the symbol we are looking for. */
- continue;
-
- switch (ELF32_ST_BIND (sym->st_info))
- {
- case STB_GLOBAL:
- /* Global definition. Just what we need. */
- *ref = sym;
- return (Elf32_Word)map->loadoffs;
- case STB_WEAK:
- /* Weak definition. Use this value if we don't find another. */
- if (! weak_value.s)
- {
- weak_value.s = sym;
- weak_value.a = (Elf32_Word)map->loadoffs;
- }
- break;
- default:
- /* Local symbols are ignored. */
- break;
- }
- }
- }
-
- if (weak_value.s == NULL && ELF32_ST_BIND ((*ref)->st_info) != STB_WEAK) {
- _dl_fdprintf(2,"%s: undefined symbol: '%s' %x\n", _dl_progname, undef_name,(*ref)->st_info);
- }
-
- *ref = weak_value.s;
- return weak_value.a;
-}
-
-
-/* Get link_map for this object. */
-static struct elf_resolve *
-elf_machine_runtime_link_map (Elf32_Addr gpreg)
-{
- struct elf_resolve *l = 0;
- Elf32_Addr *got = (Elf32_Addr *) (gpreg - 0x7ff0);
- Elf32_Word g1;
-
- g1 = ((Elf32_Word *) got)[1];
-
- if (g1 & 0x80000000)
- l = (void *) (g1 & ~0x80000000);
-#if 0
- else
- l = LOOK_UP_A_TABLE (got);
-#endif
- return l;
-}
-
-/* This function is called from assembler function _dl_runtime_resolve
- which converts special argument registers t7 ($15) and t8 ($24):
- t7 address to return to the caller of the function
- t8 index for this function symbol in .dynsym
- to usual c arguments. */
-
-Elf32_Addr
-__dl_runtime_resolve (Elf32_Word sym_index,
- Elf32_Word return_address,
- Elf32_Addr old_gpreg,
- Elf32_Addr stub_return_address)
-{
- struct elf_resolve *l = elf_machine_runtime_link_map (old_gpreg);
-
- const Elf32_Sym *const symtab
- = (const Elf32_Sym *) (l->loadoffs + l->dynamic_info[DT_SYMTAB]);
- char *strtab
- = (void *) (l->loadoffs + l->dynamic_info[DT_STRTAB]);
- Elf32_Addr *got
- = (Elf32_Addr *) (l->loadoffs + l->dynamic_info[DT_PLTGOT]);
-
- const Elf32_Word local_gotno
- = (const Elf32_Word) l->dynamic_info[DT_MIPS_LOCAL_GOTNO - DT_LOPROC + DT_NUM];
- const Elf32_Word gotsym
- = (const Elf32_Word) l->dynamic_info[DT_MIPS_GOTSYM - DT_LOPROC + DT_NUM];
-
- const Elf32_Sym *definer;
- Elf32_Addr loadbase;
- Elf32_Addr funcaddr;
- struct elf_resolve *scope, *real_next;
-
- /* Look up the symbol's run-time value. */
-
- real_next = l->next;
- if (l->dynamic_info[DT_SYMBOLIC])
- {
- l->next = _dl_loaded_modules;
- if (l->prev)
- l->prev->next = real_next;
- scope = l;
- }
- else
- scope = _dl_loaded_modules;
-
- definer = &symtab[sym_index];
- loadbase = _dl_lookup_symbol (strtab + definer->st_name, &definer,
- scope, l->libname, 0);
-
-
- /* Restore list frobnication done above for DT_SYMBOLIC. */
- l->next = real_next;
- if (l->prev)
- l->prev->next = l;
-
- /* Apply the relocation with that value. */
- funcaddr = loadbase + definer->st_value;
- *(got + local_gotno + sym_index - gotsym) = funcaddr;
-
- return funcaddr;
-}
-
-asm ("\n\
- .text\n\
- .align 2\n\
- .globl _dl_runtime_resolve\n\
- .type _dl_runtime_resolve,@function\n\
- .ent _dl_runtime_resolve\n\
-_dl_runtime_resolve:\n\
- .set noreorder\n\
- # Save old GP to $3.\n\
- move $3,$28\n\
- # Modify t9 ($25) so as to point .cpload instruction.\n\
- addu $25,8\n\
- # Compute GP.\n\
- .cpload $25\n\
- .set reorder\n\
- # Save arguments and sp value in stack.\n\
- subu $29, 40\n\
- .cprestore 32\n\
- sw $15, 36($29)\n\
- sw $4, 12($29)\n\
- sw $5, 16($29)\n\
- sw $6, 20($29)\n\
- sw $7, 24($29)\n\
- sw $16, 28($29)\n\
- move $16, $29\n\
- move $4, $24\n\
- move $5, $15\n\
- move $6, $3\n\
- move $7, $31\n\
- jal __dl_runtime_resolve\n\
- move $29, $16\n\
- lw $31, 36($29)\n\
- lw $4, 12($29)\n\
- lw $5, 16($29)\n\
- lw $6, 20($29)\n\
- lw $7, 24($29)\n\
- lw $16, 28($29)\n\
- addu $29, 40\n\
- move $25, $2\n\
- jr $25\n\
- .end _dl_runtime_resolve\n\
-");
-
-
-int
-_dl_parse_relocation_information (struct elf_resolve *tpnt, int rel_addr,
- int rel_size, int lazy)
-{
- int i;
- char *strtab;
- int reloc_type;
- int goof = 0;
- Elf32_Sym *symtab;
- const Elf32_Sym *symbol;
- const Elf32_Sym *ref;
- Elf32_Rel *rpnt;
- unsigned int *reloc_addr;
- unsigned int symbol_addr;
- int symtab_index;
- struct elf_resolve *real_next, *scope;
-
- /* Now parse the relocation information */
-
- rpnt = (Elf32_Rel *) (rel_addr + tpnt->loadoffs);
- rel_size = rel_size / sizeof (Elf32_Rel);
-
- symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadoffs);
- strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadoffs);
-
- /* Set scope. */
- real_next = tpnt->next;
- if (tpnt->dynamic_info[DT_SYMBOLIC]) {
- if (tpnt->prev)
- tpnt->prev->next = real_next;
- tpnt->next = _dl_loaded_modules;
- scope = tpnt;
- }
- else
- scope = _dl_loaded_modules;
-
- for (i = 0; i < rel_size; i++, rpnt++) {
- reloc_addr = (int *) (tpnt->loadoffs + (int) rpnt->r_offset);
- reloc_type = ELF32_R_TYPE (rpnt->r_info);
- symtab_index = ELF32_R_SYM (rpnt->r_info);
- symbol = symtab + symtab_index;
- symbol_addr = (unsigned int) tpnt->loadoffs;
- ref = symbol;
-
- if (tpnt->libtype == program_interpreter
- && (!symtab_index || _dl_symbol (strtab + symbol->st_name)))
- continue;
-
- if (symtab_index == 0xffffff)
- continue;
-
- if (symtab_index &&
- !(ELF32_ST_BIND (ref->st_info) == STB_LOCAL &&
- ELF32_ST_TYPE (ref->st_info) == STT_NOTYPE)) {
-
- symbol_addr = (unsigned int)
- _dl_lookup_symbol (strtab + symbol->st_name, &ref,
- scope, tpnt->libname, 0);
-
- /* We want to allow undefined references to weak symbols -
- this might have been intentional. We should not be
- linking local symbols here, so all bases should be
- covered. */
- if (!ref && ELF32_ST_BIND (symbol->st_info) == STB_GLOBAL) {
- _dl_fdprintf (2, "%s: can't resolve symbol '%s'\n",
- _dl_progname, strtab + symbol->st_name);
- goof++;
- }
- }
- switch (reloc_type)
- {
- case R_MIPS_NONE:
- break;
-
- case R_MIPS_REL32:
- if (ELF32_ST_BIND (symbol->st_info) == STB_LOCAL
- && (ELF32_ST_TYPE (symbol->st_info) == STT_SECTION
- || ELF32_ST_TYPE (symbol->st_info) == STT_NOTYPE)) {
- *reloc_addr += (unsigned int) tpnt->loadoffs;
- }
- else {
- *reloc_addr += ref ? symbol_addr + ref->st_value : 0;
- }
- break;
-
- default:
- _dl_fdprintf (2, "%s: can't handle reloc type ", _dl_progname);
- if (symtab_index)
- _dl_fdprintf (2, "'%s'", strtab + symbol->st_name);
- _dl_fdprintf (2, "\n");
- _dl_exit (1);
- }
-
- }
- /* Restore list frobnication done above for DT_SYMBOLIC. */
- tpnt->next = real_next;
- if (tpnt->prev)
- tpnt->prev->next = tpnt;
-
- return goof;
-}
-
-/* Relocate GOT. */
-void
-elf_machine_got_rel (struct elf_resolve *map)
-{
- Elf32_Addr *got;
- Elf32_Sym *sym = 0;
- int i, n;
- struct elf_resolve *real_next, *scope;
- char *strtab = ((void *) map->loadoffs + map->dynamic_info[DT_STRTAB]);
-
- Elf32_Addr resolve (const Elf32_Sym *sym)
- {
- const Elf32_Sym *ref;
- Elf32_Addr sym_addr;
-
- sym_addr = _dl_lookup_symbol (strtab + sym->st_name, &ref, scope,
- map->libname, 1);
- if(ref)
- return sym_addr + ref->st_value;
- else
- return 0;
- }
-
- got = (Elf32_Addr *) ((void *) map->loadoffs + map->dynamic_info[DT_PLTGOT]);
-
- /* Add the run-time display to all local got entries. */
- i = (got[1] & 0x80000000)? 2: 1;
- n = map->dynamic_info[DT_MIPS_LOCAL_GOTNO - DT_LOPROC + DT_NUM];
- while (i < n) {
- got[i++] += (Elf32_Addr)map->loadoffs;
- }
-
- /* Set scope. */
- real_next = map->next;
- if (map->dynamic_info[DT_SYMBOLIC]) {
- if (map->prev)
- map->prev->next = real_next;
- map->next = _dl_loaded_modules;
- scope = map;
- }
- else
- scope = _dl_loaded_modules;
-
- /* Handle global got entries. */
- got += n;
- sym = (Elf32_Sym *) ((void *) map->loadoffs + map->dynamic_info[DT_SYMTAB]);
- sym += map->dynamic_info[DT_MIPS_GOTSYM - DT_LOPROC + DT_NUM];
- i = (map->dynamic_info[DT_MIPS_SYMTABNO - DT_LOPROC + DT_NUM]
- - map->dynamic_info[DT_MIPS_GOTSYM - DT_LOPROC + DT_NUM]);
-
- while (i--) {
- if (sym->st_shndx == SHN_UNDEF) {
- if (ELF32_ST_TYPE (sym->st_info) == STT_FUNC) {
-#if 0 /*XXX*/
- if (sym->st_value /* && maybe_stub (sym->st_value) */) {
- *got = sym->st_value + (Elf32_Word)map->loadoffs;
- }
- else {
- *got = resolve (sym);
- }
-#else
- *got = resolve (sym);
-#endif
- }
- else /* if (*got == 0 || *got == QS) */ {
- *got = resolve (sym);
- }
- }
- else if (sym->st_shndx == SHN_COMMON) {
- *got = resolve (sym);
- }
- else if (ELF32_ST_TYPE (sym->st_info) == STT_FUNC
- /* && maybe_stub (*got) */) {
- *got += (Elf32_Word)map->loadoffs;
- }
- else {
- *got = sym->st_value + (Elf32_Word)map->loadoffs;
- }
-
- got++;
- sym++;
- }
-
- /* Restore list frobnication done above for DT_SYMBOLIC. */
- map->next = real_next;
- if (map->prev)
- map->prev->next = map;
-
- return;
-}