diff options
Diffstat (limited to 'ldso/ldso/mips')
-rw-r--r-- | ldso/ldso/mips/README | 43 | ||||
-rw-r--r-- | ldso/ldso/mips/boot1_arch.h | 5 | ||||
-rw-r--r-- | ldso/ldso/mips/dl-startup.h | 5 | ||||
-rw-r--r-- | ldso/ldso/mips/dl-syscalls.h | 30 | ||||
-rw-r--r-- | ldso/ldso/mips/dl-sysdep.h | 92 | ||||
-rw-r--r-- | ldso/ldso/mips/elfinterp.c | 49 | ||||
-rw-r--r-- | ldso/ldso/mips/ld_syscalls.h | 30 | ||||
-rw-r--r-- | ldso/ldso/mips/ld_sysdep.h | 92 |
8 files changed, 294 insertions, 52 deletions
diff --git a/ldso/ldso/mips/README b/ldso/ldso/mips/README new file mode 100644 index 000000000..b54e25183 --- /dev/null +++ b/ldso/ldso/mips/README @@ -0,0 +1,43 @@ +Almost all of the code present in these source files was taken +from GLIBC. In the descriptions below, all files mentioned are +with respect to the top level GLIBC source directory accept for +the code taken from the Linux kernel. + +boot1_arch.h +------------ +Contains code to fix up the stack pointer so that the dynamic +linker can find argc, argv and Auxillary Vector Table (AVT). +The codes is taken from the function 'RTLD_START' in the +file 'sysdeps/mips/dl-machine.h'. + +elfinterp.c +----------- +Contains '_dl_init_got' which initializes the GOT for the +application being dynamically linked and loaded. The code is +taken from the functions 'elf_machine_runtime_setup' and +'elf_machine_got_rel' in the file 'sysdeps/mips/dl-machine.h'. + +ld_syscalls.h +------------- +Contains all the macro function prototypes for the system calls +as well as the list of system calls supported. The macros were +taken from the Linux kernel source 2.4.17 found in the file +'include/asm-mips/unistd.h'. + +ld_sysdep.h +----------- +Contains bootstrap code for the dynamic linker, magic numbers +for detecting MIPS target types and some macros. The macro +function 'PERFORM_BOOTSTRAP_GOT' is used to relocate the dynamic +linker's GOT so that function calls can be made. The code is +taken from the function 'ELF_MACHINE_BEFORE_RTLD_RELOC' in the +file 'sysdep/mips/dl-machine.h'. The other macro function +'PERFORM_BOOTSTRAP_RELOC' is used to do the relocations for +the dynamic loader. The code is taken from the function +'elf_machine_rel' in the file 'sysdep/mips/dl-machine.h'. + +resolve.S +--------- +Contains the low-level assembly code for the dynamic runtime +resolver. The code is taken from the assembly code function +'_dl_runtime_resolve' in the file 'sysdesp/mips/dl-machine.h'. diff --git a/ldso/ldso/mips/boot1_arch.h b/ldso/ldso/mips/boot1_arch.h index e86ff77cf..f439ee4bc 100644 --- a/ldso/ldso/mips/boot1_arch.h +++ b/ldso/ldso/mips/boot1_arch.h @@ -13,11 +13,8 @@ _dl_boot: nop 0: .cpload $31 .set reorder - # i386 ABI book says that the first entry of GOT holds - # the address of the dynamic structure. Though MIPS ABI - # doesn't say nothing about this, I emulate this here. + # Store offset of DYNAMIC section in first entry of GOT la $4, _DYNAMIC - # Subtract OFFSET_GP_GOT sw $4, -0x7ff0($28) move $4, $29 la $8, coff diff --git a/ldso/ldso/mips/dl-startup.h b/ldso/ldso/mips/dl-startup.h index e86ff77cf..f439ee4bc 100644 --- a/ldso/ldso/mips/dl-startup.h +++ b/ldso/ldso/mips/dl-startup.h @@ -13,11 +13,8 @@ _dl_boot: nop 0: .cpload $31 .set reorder - # i386 ABI book says that the first entry of GOT holds - # the address of the dynamic structure. Though MIPS ABI - # doesn't say nothing about this, I emulate this here. + # Store offset of DYNAMIC section in first entry of GOT la $4, _DYNAMIC - # Subtract OFFSET_GP_GOT sw $4, -0x7ff0($28) move $4, $29 la $8, coff diff --git a/ldso/ldso/mips/dl-syscalls.h b/ldso/ldso/mips/dl-syscalls.h index feb54d4cf..da17d63b9 100644 --- a/ldso/ldso/mips/dl-syscalls.h +++ b/ldso/ldso/mips/dl-syscalls.h @@ -142,4 +142,34 @@ type name(atype a, btype b, ctype c, dtype d) \ return (type) -1; \ } +#define _syscall6(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e,ftype,f) \ +type name(atype a, btype b, ctype c, dtype d, etype e, ftype f) \ +{ \ + register unsigned long __v0 asm("$2") = __NR_##name; \ + register unsigned long __a0 asm("$4") = (unsigned long) a; \ + register unsigned long __a1 asm("$5") = (unsigned long) b; \ + register unsigned long __a2 asm("$6") = (unsigned long) c; \ + register unsigned long __a3 asm("$7") = (unsigned long) d; \ + \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + "lw\t$2, %6\n\t" \ + "lw\t$8, %7\n\t" \ + "subu\t$29, 32\n\t" \ + "sw\t$2, 16($29)\n\t" \ + "sw\t$8, 20($29)\n\t" \ + "li\t$2, %5\t\t\t# " #name "\n\t" \ + "syscall\n\t" \ + "addiu\t$29, 32\n\t" \ + ".set\treorder" \ + : "=&r" (__v0), "+r" (__a3) \ + : "r" (__a0), "r" (__a1), "r" (__a2), "i" (__NR_##name), \ + "m" ((unsigned long)e), "m" ((unsigned long)f) \ + : "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24"); \ + \ + if (__a3 == 0) \ + return (type) __v0; \ + return (type) -1; \ +} + #endif diff --git a/ldso/ldso/mips/dl-sysdep.h b/ldso/ldso/mips/dl-sysdep.h index 24cbc3d04..8bc6aaccd 100644 --- a/ldso/ldso/mips/dl-sysdep.h +++ b/ldso/ldso/mips/dl-sysdep.h @@ -8,36 +8,82 @@ */ #undef ELF_USES_RELOCA + /* * Get a pointer to the argv array. On many platforms this can be just * the address if the first argument, on other platforms we need to * do something a little more subtle here. */ -#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long*) ARGS) +#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long *) ARGS) + /* - * Initialization sequence for a GOT. + * Initialization sequence for the application GOT. */ -#define INIT_GOT(GOT_BASE,MODULE) \ -{ \ - GOT_BASE[0] = (unsigned long) _dl_linux_resolve; \ - GOT_BASE[1] = (unsigned long) MODULE; \ -} +#define INIT_GOT(GOT_BASE,MODULE) _dl_init_got(GOT_BASE,MODULE) + + +/* + * Here is a macro to perform the GOT relocation. This is only + * used when bootstrapping the dynamic loader. + */ +#define PERFORM_BOOTSTRAP_GOT(got) \ +do { \ + Elf32_Sym *sym; \ + unsigned long i; \ + \ + /* Add load address displacement to all local GOT entries */ \ + i = 2; \ + while (i < mips_local_gotno) \ + got[i++] += load_addr; \ + \ + /* Handle global GOT entries */ \ + got += mips_local_gotno; \ + sym = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + \ + load_addr) + mips_gotsym; \ + i = mips_symtabno - mips_gotsym; \ + \ + while (i--) { \ + if (sym->st_shndx == SHN_UNDEF || \ + sym->st_shndx == SHN_COMMON) \ + *got = load_addr + sym->st_value; \ + else if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC && \ + *got != sym->st_value) \ + *got += load_addr; \ + else if (ELF32_ST_TYPE(sym->st_info) == STT_SECTION) { \ + if (sym->st_other == 0) \ + *got += load_addr; \ + } \ + else \ + *got = load_addr + sym->st_value; \ + \ + got++; \ + sym++; \ + } \ +} while (0) + /* * Here is a macro to perform a relocation. This is only used when - * bootstrapping the dynamic loader. RELP is the relocation that we - * are performing, REL is the pointer to the address we are relocating. - * SYMBOL is the symbol involved in the relocation, and LOAD is the - * load address. - * - * !!!NOTE!!! - * - * For MIPS, we don't have any DT_JMPREL or DT_PLTRELSZ dynamic - * entries, so this macro function is empty. The code contained - * in elfinterp.c does the real relocation work. + * bootstrapping the dynamic loader. */ -#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) +#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \ + switch(ELF32_R_TYPE((RELP)->r_info)) { \ + case R_MIPS_REL32: \ + if (symtab_index) { \ + if (symtab_index < mips_gotsym) \ + *REL += SYMBOL + LOAD; \ + } \ + else { \ + *REL += LOAD; \ + } \ + break; \ + case R_MIPS_NONE: \ + break; \ + default: \ + SEND_STDERR("Aiieeee!"); \ + _dl_exit(1); \ + } /* @@ -45,19 +91,21 @@ * is done. This routine has to exit the current function, then * call the _dl_elf_main function. */ - #define START() return (void) _dl_elf_main; - /* Here we define the magic numbers that this dynamic loader should accept */ - #define MAGIC1 EM_MIPS #define MAGIC2 EM_MIPS_RS3_LE + + /* Used for error messages */ #define ELF_TARGET "MIPS" + struct elf_resolve; -unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry); +extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, + int reloc_entry); +void _dl_init_got(unsigned long *got, struct elf_resolve *tpnt); #define do_rem(result, n, base) result = (n % base) diff --git a/ldso/ldso/mips/elfinterp.c b/ldso/ldso/mips/elfinterp.c new file mode 100644 index 000000000..c38a7ffa2 --- /dev/null +++ b/ldso/ldso/mips/elfinterp.c @@ -0,0 +1,49 @@ +/* Run an ELF binary on a linux system. + + Copyright (C) 1993, Eric Youngdale. + Copyright (C) 2002, Steven J. Hill (sjhill@realitydiluted.com) + + 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 linux 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. */ + + +extern int _dl_linux_resolve(void); + +void _dl_init_got(unsigned long *got, struct elf_resolve *tpnt) +{ + return; +} + +unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) +{ + return 0; +} + +int _dl_parse_relocation_information(struct elf_resolve *tpnt, + unsigned long rel_addr, unsigned long rel_size, int type) +{ + return 1; +} diff --git a/ldso/ldso/mips/ld_syscalls.h b/ldso/ldso/mips/ld_syscalls.h index feb54d4cf..da17d63b9 100644 --- a/ldso/ldso/mips/ld_syscalls.h +++ b/ldso/ldso/mips/ld_syscalls.h @@ -142,4 +142,34 @@ type name(atype a, btype b, ctype c, dtype d) \ return (type) -1; \ } +#define _syscall6(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e,ftype,f) \ +type name(atype a, btype b, ctype c, dtype d, etype e, ftype f) \ +{ \ + register unsigned long __v0 asm("$2") = __NR_##name; \ + register unsigned long __a0 asm("$4") = (unsigned long) a; \ + register unsigned long __a1 asm("$5") = (unsigned long) b; \ + register unsigned long __a2 asm("$6") = (unsigned long) c; \ + register unsigned long __a3 asm("$7") = (unsigned long) d; \ + \ + __asm__ volatile ( \ + ".set\tnoreorder\n\t" \ + "lw\t$2, %6\n\t" \ + "lw\t$8, %7\n\t" \ + "subu\t$29, 32\n\t" \ + "sw\t$2, 16($29)\n\t" \ + "sw\t$8, 20($29)\n\t" \ + "li\t$2, %5\t\t\t# " #name "\n\t" \ + "syscall\n\t" \ + "addiu\t$29, 32\n\t" \ + ".set\treorder" \ + : "=&r" (__v0), "+r" (__a3) \ + : "r" (__a0), "r" (__a1), "r" (__a2), "i" (__NR_##name), \ + "m" ((unsigned long)e), "m" ((unsigned long)f) \ + : "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24"); \ + \ + if (__a3 == 0) \ + return (type) __v0; \ + return (type) -1; \ +} + #endif diff --git a/ldso/ldso/mips/ld_sysdep.h b/ldso/ldso/mips/ld_sysdep.h index 24cbc3d04..8bc6aaccd 100644 --- a/ldso/ldso/mips/ld_sysdep.h +++ b/ldso/ldso/mips/ld_sysdep.h @@ -8,36 +8,82 @@ */ #undef ELF_USES_RELOCA + /* * Get a pointer to the argv array. On many platforms this can be just * the address if the first argument, on other platforms we need to * do something a little more subtle here. */ -#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long*) ARGS) +#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long *) ARGS) + /* - * Initialization sequence for a GOT. + * Initialization sequence for the application GOT. */ -#define INIT_GOT(GOT_BASE,MODULE) \ -{ \ - GOT_BASE[0] = (unsigned long) _dl_linux_resolve; \ - GOT_BASE[1] = (unsigned long) MODULE; \ -} +#define INIT_GOT(GOT_BASE,MODULE) _dl_init_got(GOT_BASE,MODULE) + + +/* + * Here is a macro to perform the GOT relocation. This is only + * used when bootstrapping the dynamic loader. + */ +#define PERFORM_BOOTSTRAP_GOT(got) \ +do { \ + Elf32_Sym *sym; \ + unsigned long i; \ + \ + /* Add load address displacement to all local GOT entries */ \ + i = 2; \ + while (i < mips_local_gotno) \ + got[i++] += load_addr; \ + \ + /* Handle global GOT entries */ \ + got += mips_local_gotno; \ + sym = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + \ + load_addr) + mips_gotsym; \ + i = mips_symtabno - mips_gotsym; \ + \ + while (i--) { \ + if (sym->st_shndx == SHN_UNDEF || \ + sym->st_shndx == SHN_COMMON) \ + *got = load_addr + sym->st_value; \ + else if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC && \ + *got != sym->st_value) \ + *got += load_addr; \ + else if (ELF32_ST_TYPE(sym->st_info) == STT_SECTION) { \ + if (sym->st_other == 0) \ + *got += load_addr; \ + } \ + else \ + *got = load_addr + sym->st_value; \ + \ + got++; \ + sym++; \ + } \ +} while (0) + /* * Here is a macro to perform a relocation. This is only used when - * bootstrapping the dynamic loader. RELP is the relocation that we - * are performing, REL is the pointer to the address we are relocating. - * SYMBOL is the symbol involved in the relocation, and LOAD is the - * load address. - * - * !!!NOTE!!! - * - * For MIPS, we don't have any DT_JMPREL or DT_PLTRELSZ dynamic - * entries, so this macro function is empty. The code contained - * in elfinterp.c does the real relocation work. + * bootstrapping the dynamic loader. */ -#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) +#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD) \ + switch(ELF32_R_TYPE((RELP)->r_info)) { \ + case R_MIPS_REL32: \ + if (symtab_index) { \ + if (symtab_index < mips_gotsym) \ + *REL += SYMBOL + LOAD; \ + } \ + else { \ + *REL += LOAD; \ + } \ + break; \ + case R_MIPS_NONE: \ + break; \ + default: \ + SEND_STDERR("Aiieeee!"); \ + _dl_exit(1); \ + } /* @@ -45,19 +91,21 @@ * is done. This routine has to exit the current function, then * call the _dl_elf_main function. */ - #define START() return (void) _dl_elf_main; - /* Here we define the magic numbers that this dynamic loader should accept */ - #define MAGIC1 EM_MIPS #define MAGIC2 EM_MIPS_RS3_LE + + /* Used for error messages */ #define ELF_TARGET "MIPS" + struct elf_resolve; -unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry); +extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, + int reloc_entry); +void _dl_init_got(unsigned long *got, struct elf_resolve *tpnt); #define do_rem(result, n, base) result = (n % base) |