diff --git a/include/link_elf.h b/include/link_elf.h index 6725cacc745f..813defa6759e 100644 --- a/include/link_elf.h +++ b/include/link_elf.h @@ -1,4 +1,4 @@ -/* $NetBSD: link_elf.h,v 1.1 1996/12/16 20:37:59 cgd Exp $ */ +/* $NetBSD: link_elf.h,v 1.2 1998/03/25 04:13:01 mhitch Exp $ */ /* * This only exists for GDB. @@ -10,6 +10,9 @@ struct link_map { caddr_t l_addr; /* Base Address of library */ +#ifdef __mips__ + caddr_t l_offs; /* Load Offset of library */ +#endif const char *l_name; /* Absolute Path to Library */ void *l_ld; /* Pointer to .dynamic in memory */ struct link_map *l_next, *l_prev; /* linked list of of mapped libs */ diff --git a/libexec/ld.elf_so/Makefile b/libexec/ld.elf_so/Makefile index 3af424e48e71..36c8b405dfa9 100644 --- a/libexec/ld.elf_so/Makefile +++ b/libexec/ld.elf_so/Makefile @@ -1,9 +1,8 @@ -# $NetBSD: Makefile,v 1.11 1998/02/23 10:09:32 jonathan Exp $ +# $NetBSD: Makefile,v 1.12 1998/03/25 04:13:01 mhitch Exp $ .include # for OBJECT_FMT definition -.if ((${OBJECT_FMT} == "ELF") && !defined(NOSHLIB)) && \ - (${MACHINE_ARCH} != "mips") # mips uses non-native ld.so +.if ((${OBJECT_FMT} == "ELF") && !defined(NOSHLIB)) PROG= ld.elf_so .endif diff --git a/libexec/ld.elf_so/README b/libexec/ld.elf_so/README index 8b0b496f569b..c00fc5f77f57 100644 --- a/libexec/ld.elf_so/README +++ b/libexec/ld.elf_so/README @@ -1,4 +1,4 @@ -$NetBSD: README,v 1.1 1996/12/16 20:37:56 cgd Exp $ +$NetBSD: README,v 1.2 1998/03/25 04:13:01 mhitch Exp $ BUGS/PROBLEMS: @@ -38,7 +38,7 @@ BUGS/PROBLEMS: TO DO: -* Support for other platforms (e.g. mips) +* Support for other platforms * Support for coexistance of 32-bit and 64-bit ELF on platforms that can do that. @@ -47,3 +47,5 @@ TO DO: * Possible support for ldd (standalone operation) and program loading a la the glibc shared loader. + +* Support for relocating ld.elf_so on mips diff --git a/libexec/ld.elf_so/arch/mips/Makefile.inc b/libexec/ld.elf_so/arch/mips/Makefile.inc new file mode 100644 index 000000000000..51e5ef39eb33 --- /dev/null +++ b/libexec/ld.elf_so/arch/mips/Makefile.inc @@ -0,0 +1,15 @@ +# $NetBSD: Makefile.inc,v 1.1 1998/03/25 04:12:32 mhitch Exp $ + +SRCS+= rtld_start.S mips_reloc.c + +CPPFLAGS+= -mabicalls -G0 -fPIC -DELFSIZE=32 -I${.CURDIR} + +.if (${MACHINE} == "newsmips") +# UGH! ld.so.script specifies little-endian; need to override that here +LDFLAGS+= -EB +.endif + +LDFLAGS+= -Bshareable -Bsymbolic -e .rtld_start --script mips/ld.so.script + +# Link ld.so for backward compatibility with old binaries +LINKS+= ${DESTDIR}/usr/libexec/${PROG} ${DESTDIR}/usr/libexec/ld.so diff --git a/libexec/ld.elf_so/arch/mips/ld.so.script b/libexec/ld.elf_so/arch/mips/ld.so.script new file mode 100644 index 000000000000..2710ed96568f --- /dev/null +++ b/libexec/ld.elf_so/arch/mips/ld.so.script @@ -0,0 +1,152 @@ +/* $NetBSD: ld.so.script,v 1.1 1998/03/25 04:12:32 mhitch Exp $ */ + +/* ldscript for MIPS ld.elf_so */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_start) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/mips-dec-netbsd/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x5ffe0000 + SIZEOF_HEADERS; + .reginfo : { *(.reginfo) } + .dynamic : { *(.dynamic) } + .dynstr : { *(.dynstr) } + .dynsym : { *(.dynsym) } + .hash : { *(.hash) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + .init : { *(.init) } =0 + .text : + { + _ftext = . ; + *(.text) + *(.stub) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + *(.mips16.fn.*) + *(.mips16.call.*) + } =0 + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0 + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. It would + be more correct to do this: + . = 0x10000000; + The current expression does not correctly handle the case of a + text segment ending precisely at the end of a page; it causes the + data segment to skip a page. The above expression does not have + this problem, but it will currently (2/95) cause BFD to allocate + a single segment, combining both text and data, for this case. + This will prevent the text segment from being shared among + multiple executions of the program; I think that is more + important than losing a page of the virtual address space (note + that no actual memory is lost; the page which is skipped can not + be referenced). */ + /* "Fix" for ld.so on NetBSD: + The binutils 2.8.1 ld aligns the data segment at 1MB (0x40000), but + the alignment specified in the ELF program headers specifies 4K + (0x1000). The NetBSD kernel forces the data section to be loaded + by the alignment in the program header, which thus does not match + the alignment done by ld. This line is the only difference from + the script built in to ld: force the data section alignment to + match what bfd puts into the program headers. */ + . = ALIGN(0x1000) + (ALIGN(8) & (0x1000 - 1)); + .data : + { + _fdata = . ; + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + _gp = ALIGN(16) + 0x7ff0; + .got : + { + *(.got.plt) *(.got) + } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + .lit8 : { *(.lit8) } + .lit4 : { *(.lit4) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + _fbss = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* These are needed for ELF backends which have not yet been + converted to the new style linker. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ + .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } + .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } +} diff --git a/libexec/ld.elf_so/arch/mips/mips_reloc.c b/libexec/ld.elf_so/arch/mips/mips_reloc.c new file mode 100644 index 000000000000..6047cfe1b213 --- /dev/null +++ b/libexec/ld.elf_so/arch/mips/mips_reloc.c @@ -0,0 +1,123 @@ +/* $NetBSD: mips_reloc.c,v 1.1 1998/03/25 04:12:32 mhitch Exp $ */ + +/* + * Copyright 1997 Michael L. Hitch + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 +#include + +#include "debug.h" +#include "rtld.h" + +/* + * Relocate a MIPS GOT + */ + +void +_rtld_relocate_mips_got(obj) + Obj_Entry *obj; +{ + Elf_Addr *got = obj->pltgot; + const Elf_Sym *sym = obj->symtab; + const Elf_Sym *def; + const Obj_Entry *defobj; + int i; + + i = (got[1] & 0x80000000) ? 2 : 1; + /* Relocate the local GOT entries */ + while (i < obj->local_gotno) + got[i++] += (Elf_Word)obj->relocbase; + got += obj->local_gotno; + i = obj->symtabno - obj->gotsym; + sym += obj->gotsym; + /* Now do the global GOT entries */ + while (i--) { + def = _rtld_find_symdef(_rtld_objlist, 0, + sym->st_name + obj->strtab, obj, &defobj, true); + if (def != NULL) { + if (sym->st_shndx == Elf_eshn_undefined) { +#if 0 /* These don't seem to work? */ + + if (ELF_SYM_TYPE(sym->st_info) == + Elf_estt_func) { + if (sym->st_value) + *got = sym->st_value + + (Elf_Word)obj->relocbase; + else + *got = def->st_value + + (Elf_Word)defobj->relocbase; + } else +#endif + *got = def->st_value + + (Elf_Word)defobj->relocbase; + } else if (sym->st_shndx == Elf_eshn_common) { + *got = def->st_value + + (Elf_Word)defobj->relocbase; + } else if (ELF_SYM_TYPE(sym->st_info) == Elf_estt_func + && *got != sym->st_value) { + *got += (Elf_Word)obj->relocbase; + } else if (ELF_SYM_TYPE(sym->st_info) == + Elf_estt_section && ELF_SYM_BIND(sym->st_info) == + Elf_estb_global) { + if (sym->st_shndx == Elf_eshn_absolute) + *got = sym->st_value + + (Elf_Word)obj->relocbase; + /* else SGI stuff ignored */ + } else + *got = def->st_value + + (Elf_Word)defobj->relocbase; + } + ++sym; + ++got; + } +} + +/* + * _rtld_bind_mips(symbol_index, return_address, old_gp, stub_return_addr) + */ + +caddr_t +_rtld_bind_mips(a0, a1, a2, a3) + Elf_Word a0; + Elf_Addr a1, a2, a3; +{ + Elf_Addr *u = (Elf_Addr *)(a2 - 0x7ff0); + Obj_Entry *obj = (Obj_Entry *)(u[1] & 0x7fffffff); + const Elf_Sym *def; + const Obj_Entry *defobj; + + def = _rtld_find_symdef(_rtld_objlist, a0 << 8, NULL, obj, &defobj, + true); + if (def) { + u[obj->local_gotno + a0 - obj->gotsym] = (Elf_Addr) + (def->st_value + defobj->relocbase); + return((caddr_t)(def->st_value + defobj->relocbase)); + } + + return(NULL); /* XXX */ +} diff --git a/libexec/ld.elf_so/arch/mips/rtld_start.S b/libexec/ld.elf_so/arch/mips/rtld_start.S new file mode 100644 index 000000000000..403fcd59242d --- /dev/null +++ b/libexec/ld.elf_so/arch/mips/rtld_start.S @@ -0,0 +1,88 @@ +/* $NetBSD: rtld_start.S,v 1.1 1998/03/25 04:12:32 mhitch Exp $ */ + +/* + * Copyright 1997 Michael L. Hitch + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 +#include + +LEAF(rtld_start) + .set noreorder + + .cpload t9 + addu sp, sp, -12 # adjust stack pointer + .cprestore 0 # 0(sp) for gp + # 4(sp) for atexit + # 8(sp) for obj_main + move s0,a0 # save stack pointer from a0 + addu a0, sp, 4 # _rtld argument + jal _C_LABEL(_rtld) # v0 = _rtld(sp) + move s1,a3 # save ps_strings pointer + lw a1, 4(sp) # our atexit function + lw a2, 8(sp) # obj_main entry + addu sp, sp,12 # readjust stack + move a0,s0 # stack pointer + move t9,v0 + jr t9 # _start(sp, cleanup, obj); + move a3,s1 # restore ps_strings + +END(rtld_start) + + .globl _rtld_bind_start + .ent _rtld_bind_start +_rtld_bind_start: + + move v1,gp # save old GP + add t9,8 # modify T9 to point at .cpload + .cpload t9 + subu sp,40 # save arguments and sp value in stack + .cprestore 32 + sw t7,36(sp) + sw a0,12(sp) + sw a1,16(sp) + sw a2,20(sp) + sw a3,24(sp) + sw s0,28(sp) + move s0,sp + move a0,t8 # symbol index + move a1,t7 # old RA + move a2,v1 # old GP + move a3,ra # current RA + jal _C_LABEL(_rtld_bind_mips) + nop + move sp,s0 + lw ra,36(sp) + lw a0,12(sp) + lw a1,16(sp) + lw a2,20(sp) + lw a3,24(sp) + lw s0,28(sp) + addu sp,40 + move t9,v0 + jr t9 + nop + .end _rtld_bind_start diff --git a/libexec/ld.elf_so/headers.c b/libexec/ld.elf_so/headers.c index 6f860df57b65..6937114acd72 100644 --- a/libexec/ld.elf_so/headers.c +++ b/libexec/ld.elf_so/headers.c @@ -1,4 +1,4 @@ -/* $NetBSD: headers.c,v 1.1 1996/12/16 20:37:58 cgd Exp $ */ +/* $NetBSD: headers.c,v 1.2 1998/03/25 04:13:01 mhitch Exp $ */ /* * Copyright 1996 John D. Polstra. @@ -200,6 +200,26 @@ _rtld_digest_dynamic( dynp->d_un.d_ptr = (Elf_Addr) &_rtld_debug; #endif break; + +#if defined(__mips__) + case DT_MIPS_LOCAL_GOTNO: + obj->local_gotno = dynp->d_un.d_val; + break; + + case DT_MIPS_SYMTABNO: + obj->symtabno = dynp->d_un.d_val; + break; + + case DT_MIPS_GOTSYM: + obj->gotsym = dynp->d_un.d_val; + break; + + case DT_MIPS_RLD_MAP: +#ifdef RTLD_LOADER + *((Elf_Addr *)(dynp->d_un.d_ptr)) = (Elf_Addr) &_rtld_debug; +#endif + break; +#endif } } diff --git a/libexec/ld.elf_so/link.h b/libexec/ld.elf_so/link.h index afd609ae2215..628d1ed53431 100644 --- a/libexec/ld.elf_so/link.h +++ b/libexec/ld.elf_so/link.h @@ -1,4 +1,4 @@ -/* $NetBSD: link.h,v 1.1 1996/12/16 20:37:59 cgd Exp $ */ +/* $NetBSD: link.h,v 1.2 1998/03/25 04:13:01 mhitch Exp $ */ /* * This only exists for GDB. @@ -10,6 +10,9 @@ struct link_map { caddr_t l_addr; /* Base Address of library */ +#ifdef __mips__ + caddr_t l_offs; /* Load Offset of library */ +#endif const char *l_name; /* Absolute Path to Library */ void *l_ld; /* Pointer to .dynamic in memory */ struct link_map *l_next, *l_prev; /* linked list of of mapped libs */ diff --git a/libexec/ld.elf_so/mips/Makefile.inc b/libexec/ld.elf_so/mips/Makefile.inc new file mode 100644 index 000000000000..51e5ef39eb33 --- /dev/null +++ b/libexec/ld.elf_so/mips/Makefile.inc @@ -0,0 +1,15 @@ +# $NetBSD: Makefile.inc,v 1.1 1998/03/25 04:12:32 mhitch Exp $ + +SRCS+= rtld_start.S mips_reloc.c + +CPPFLAGS+= -mabicalls -G0 -fPIC -DELFSIZE=32 -I${.CURDIR} + +.if (${MACHINE} == "newsmips") +# UGH! ld.so.script specifies little-endian; need to override that here +LDFLAGS+= -EB +.endif + +LDFLAGS+= -Bshareable -Bsymbolic -e .rtld_start --script mips/ld.so.script + +# Link ld.so for backward compatibility with old binaries +LINKS+= ${DESTDIR}/usr/libexec/${PROG} ${DESTDIR}/usr/libexec/ld.so diff --git a/libexec/ld.elf_so/mips/ld.so.script b/libexec/ld.elf_so/mips/ld.so.script new file mode 100644 index 000000000000..2710ed96568f --- /dev/null +++ b/libexec/ld.elf_so/mips/ld.so.script @@ -0,0 +1,152 @@ +/* $NetBSD: ld.so.script,v 1.1 1998/03/25 04:12:32 mhitch Exp $ */ + +/* ldscript for MIPS ld.elf_so */ +OUTPUT_FORMAT("elf32-littlemips", "elf32-bigmips", + "elf32-littlemips") +OUTPUT_ARCH(mips) +ENTRY(_start) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/mips-dec-netbsd/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x5ffe0000 + SIZEOF_HEADERS; + .reginfo : { *(.reginfo) } + .dynamic : { *(.dynamic) } + .dynstr : { *(.dynstr) } + .dynsym : { *(.dynsym) } + .hash : { *(.hash) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + .init : { *(.init) } =0 + .text : + { + _ftext = . ; + *(.text) + *(.stub) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + *(.mips16.fn.*) + *(.mips16.call.*) + } =0 + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0 + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. It would + be more correct to do this: + . = 0x10000000; + The current expression does not correctly handle the case of a + text segment ending precisely at the end of a page; it causes the + data segment to skip a page. The above expression does not have + this problem, but it will currently (2/95) cause BFD to allocate + a single segment, combining both text and data, for this case. + This will prevent the text segment from being shared among + multiple executions of the program; I think that is more + important than losing a page of the virtual address space (note + that no actual memory is lost; the page which is skipped can not + be referenced). */ + /* "Fix" for ld.so on NetBSD: + The binutils 2.8.1 ld aligns the data segment at 1MB (0x40000), but + the alignment specified in the ELF program headers specifies 4K + (0x1000). The NetBSD kernel forces the data section to be loaded + by the alignment in the program header, which thus does not match + the alignment done by ld. This line is the only difference from + the script built in to ld: force the data section alignment to + match what bfd puts into the program headers. */ + . = ALIGN(0x1000) + (ALIGN(8) & (0x1000 - 1)); + .data : + { + _fdata = . ; + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + _gp = ALIGN(16) + 0x7ff0; + .got : + { + *(.got.plt) *(.got) + } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + .lit8 : { *(.lit8) } + .lit4 : { *(.lit4) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + _fbss = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); + /* These are needed for ELF backends which have not yet been + converted to the new style linker. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ + .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } + .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } +} diff --git a/libexec/ld.elf_so/mips/mips_reloc.c b/libexec/ld.elf_so/mips/mips_reloc.c new file mode 100644 index 000000000000..6047cfe1b213 --- /dev/null +++ b/libexec/ld.elf_so/mips/mips_reloc.c @@ -0,0 +1,123 @@ +/* $NetBSD: mips_reloc.c,v 1.1 1998/03/25 04:12:32 mhitch Exp $ */ + +/* + * Copyright 1997 Michael L. Hitch + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 +#include + +#include "debug.h" +#include "rtld.h" + +/* + * Relocate a MIPS GOT + */ + +void +_rtld_relocate_mips_got(obj) + Obj_Entry *obj; +{ + Elf_Addr *got = obj->pltgot; + const Elf_Sym *sym = obj->symtab; + const Elf_Sym *def; + const Obj_Entry *defobj; + int i; + + i = (got[1] & 0x80000000) ? 2 : 1; + /* Relocate the local GOT entries */ + while (i < obj->local_gotno) + got[i++] += (Elf_Word)obj->relocbase; + got += obj->local_gotno; + i = obj->symtabno - obj->gotsym; + sym += obj->gotsym; + /* Now do the global GOT entries */ + while (i--) { + def = _rtld_find_symdef(_rtld_objlist, 0, + sym->st_name + obj->strtab, obj, &defobj, true); + if (def != NULL) { + if (sym->st_shndx == Elf_eshn_undefined) { +#if 0 /* These don't seem to work? */ + + if (ELF_SYM_TYPE(sym->st_info) == + Elf_estt_func) { + if (sym->st_value) + *got = sym->st_value + + (Elf_Word)obj->relocbase; + else + *got = def->st_value + + (Elf_Word)defobj->relocbase; + } else +#endif + *got = def->st_value + + (Elf_Word)defobj->relocbase; + } else if (sym->st_shndx == Elf_eshn_common) { + *got = def->st_value + + (Elf_Word)defobj->relocbase; + } else if (ELF_SYM_TYPE(sym->st_info) == Elf_estt_func + && *got != sym->st_value) { + *got += (Elf_Word)obj->relocbase; + } else if (ELF_SYM_TYPE(sym->st_info) == + Elf_estt_section && ELF_SYM_BIND(sym->st_info) == + Elf_estb_global) { + if (sym->st_shndx == Elf_eshn_absolute) + *got = sym->st_value + + (Elf_Word)obj->relocbase; + /* else SGI stuff ignored */ + } else + *got = def->st_value + + (Elf_Word)defobj->relocbase; + } + ++sym; + ++got; + } +} + +/* + * _rtld_bind_mips(symbol_index, return_address, old_gp, stub_return_addr) + */ + +caddr_t +_rtld_bind_mips(a0, a1, a2, a3) + Elf_Word a0; + Elf_Addr a1, a2, a3; +{ + Elf_Addr *u = (Elf_Addr *)(a2 - 0x7ff0); + Obj_Entry *obj = (Obj_Entry *)(u[1] & 0x7fffffff); + const Elf_Sym *def; + const Obj_Entry *defobj; + + def = _rtld_find_symdef(_rtld_objlist, a0 << 8, NULL, obj, &defobj, + true); + if (def) { + u[obj->local_gotno + a0 - obj->gotsym] = (Elf_Addr) + (def->st_value + defobj->relocbase); + return((caddr_t)(def->st_value + defobj->relocbase)); + } + + return(NULL); /* XXX */ +} diff --git a/libexec/ld.elf_so/mips/rtld_start.S b/libexec/ld.elf_so/mips/rtld_start.S new file mode 100644 index 000000000000..403fcd59242d --- /dev/null +++ b/libexec/ld.elf_so/mips/rtld_start.S @@ -0,0 +1,88 @@ +/* $NetBSD: rtld_start.S,v 1.1 1998/03/25 04:12:32 mhitch Exp $ */ + +/* + * Copyright 1997 Michael L. Hitch + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 +#include + +LEAF(rtld_start) + .set noreorder + + .cpload t9 + addu sp, sp, -12 # adjust stack pointer + .cprestore 0 # 0(sp) for gp + # 4(sp) for atexit + # 8(sp) for obj_main + move s0,a0 # save stack pointer from a0 + addu a0, sp, 4 # _rtld argument + jal _C_LABEL(_rtld) # v0 = _rtld(sp) + move s1,a3 # save ps_strings pointer + lw a1, 4(sp) # our atexit function + lw a2, 8(sp) # obj_main entry + addu sp, sp,12 # readjust stack + move a0,s0 # stack pointer + move t9,v0 + jr t9 # _start(sp, cleanup, obj); + move a3,s1 # restore ps_strings + +END(rtld_start) + + .globl _rtld_bind_start + .ent _rtld_bind_start +_rtld_bind_start: + + move v1,gp # save old GP + add t9,8 # modify T9 to point at .cpload + .cpload t9 + subu sp,40 # save arguments and sp value in stack + .cprestore 32 + sw t7,36(sp) + sw a0,12(sp) + sw a1,16(sp) + sw a2,20(sp) + sw a3,24(sp) + sw s0,28(sp) + move s0,sp + move a0,t8 # symbol index + move a1,t7 # old RA + move a2,v1 # old GP + move a3,ra # current RA + jal _C_LABEL(_rtld_bind_mips) + nop + move sp,s0 + lw ra,36(sp) + lw a0,12(sp) + lw a1,16(sp) + lw a2,20(sp) + lw a3,24(sp) + lw s0,28(sp) + addu sp,40 + move t9,v0 + jr t9 + nop + .end _rtld_bind_start diff --git a/libexec/ld.elf_so/reloc.c b/libexec/ld.elf_so/reloc.c index a10f58f75612..5f38bf6e5d10 100644 --- a/libexec/ld.elf_so/reloc.c +++ b/libexec/ld.elf_so/reloc.c @@ -1,4 +1,4 @@ -/* $NetBSD: reloc.c,v 1.1 1996/12/16 20:38:02 cgd Exp $ */ +/* $NetBSD: reloc.c,v 1.2 1998/03/25 04:13:01 mhitch Exp $ */ /* * Copyright 1996 John D. Polstra. @@ -52,6 +52,7 @@ #include "debug.h" #include "rtld.h" +#ifdef __alpha__ static int _rtld_do_copy_relocation( const Obj_Entry *dstobj, @@ -80,6 +81,7 @@ _rtld_do_copy_relocation( memcpy(dstaddr, srcaddr, size); return 0; } +#endif /* __alpha__ */ /* * Process the special R_xxx_COPY relocations in the main program. These @@ -94,6 +96,7 @@ _rtld_do_copy_relocations( { assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */ +#ifdef __alpha__ /* jrs */ if (dstobj->rel != NULL) { const Elf_Rel *rel; for (rel = dstobj->rel; rel < dstobj->rellim; ++rel) { @@ -117,6 +120,7 @@ _rtld_do_copy_relocations( } } } +#endif /* jrs */ return 0; } @@ -182,7 +186,7 @@ _rtld_relocate_nonplt_object( *where = tmp_value; break; } -#endif +/*#endif*/ case R_TYPE(GLOB_DAT): { @@ -209,7 +213,6 @@ _rtld_relocate_nonplt_object( break; } - case R_TYPE(COPY): { /* * These are deferred until all other relocations have @@ -224,6 +227,33 @@ _rtld_relocate_nonplt_object( } break; } +#endif /* __alpha__ */ + +#ifdef __mips__ + case R_TYPE(REL32): { + /* 32-bit PC-relative reference */ + + const Elf_Sym *def; + const Obj_Entry *defobj; + + def = obj->symtab + ELF_R_SYM(rela->r_info); + + if (ELF_SYM_BIND(def->st_info) == Elf_estb_local && + (ELF_SYM_TYPE(def->st_info) == Elf_estt_section || + ELF_SYM_TYPE(def->st_info) == Elf_estt_notype)) { + *where += (Elf_Addr) obj->relocbase; + } else { +/* XXX maybe do something re: bootstrapping? */ + def = _rtld_find_symdef(_rtld_objlist, rela->r_info, NULL, obj, + &defobj, false); + if (def == NULL) + return -1; + *where += (Elf_Addr)(defobj->relocbase + def->st_value); + } + break; + } + +#endif /* mips */ default: { const Elf_Sym *def; @@ -252,6 +282,8 @@ _rtld_relocate_plt_object( Elf_Addr new_value; /* Fully resolve procedure addresses now */ + +#if defined(__alpha__) /* (jrs) */ if (bind_now || obj->pltgot == NULL) { const Elf_Sym *def; const Obj_Entry *defobj; @@ -268,7 +300,9 @@ _rtld_relocate_plt_object( defobj->strtab + def->st_name, obj->path, new_value, defobj->path); #endif - } else if (!obj->mainprog) { + } else +#endif /* __alpha__ (jrs) */ + if (!obj->mainprog) { /* Just relocate the GOT slots pointing into the PLT */ new_value = *where + (Elf_Addr) (obj->relocbase); } else { @@ -352,6 +386,12 @@ _rtld_relocate_objects( Elf_RelA ourrela; ourrela.r_info = rel->r_info; ourrela.r_offset = rel->r_offset; +#if defined(__mips__) + /* rel->r_offset is not valid on mips? */ + if (ELF_R_TYPE(ourrela.r_info) == R_TYPE(NONE)) + ourrela.r_addend = 0; + else +#endif ourrela.r_addend = *(Elf_Word *) (obj->relocbase + rel->r_offset); if (_rtld_relocate_nonplt_object(obj, &ourrela) < 0) @@ -423,6 +463,13 @@ _rtld_relocate_objects( obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start; /* Identify this shared object */ obj->pltgot[3] = (Elf_Addr) obj; +#endif +#if defined(__mips__) + _rtld_relocate_mips_got(obj); + + obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start; + /* XXX only if obj->pltgot[1] & 0x80000000 ?? */ + obj->pltgot[1] |= (Elf_Addr) obj; #endif } } diff --git a/libexec/ld.elf_so/rtld.c b/libexec/ld.elf_so/rtld.c index e8d188a832d0..ec6d78cb0a0a 100644 --- a/libexec/ld.elf_so/rtld.c +++ b/libexec/ld.elf_so/rtld.c @@ -1,4 +1,4 @@ -/* $NetBSD: rtld.c,v 1.5 1997/10/08 08:55:37 mrg Exp $ */ +/* $NetBSD: rtld.c,v 1.6 1998/03/25 04:13:02 mhitch Exp $ */ /* * Copyright 1996 John D. Polstra. @@ -138,7 +138,12 @@ _rtld_init( _rtld_objself.path = _rtld_path; _rtld_objself.rtld = true; _rtld_objself.mapbase = mapbase; +#ifdef __mips__ + /* mips ld.so currently linked at load address, so no relocation needed */ + _rtld_objself.relocbase = 0; +#else _rtld_objself.relocbase = mapbase; +#endif _rtld_objself.pltgot = NULL; #ifdef OLD_GOT _rtld_objself.dynamic = (Elf_Dyn *) _GLOBAL_OFFSET_TABLE_[0]; @@ -152,7 +157,9 @@ _rtld_init( _rtld_objself.pltgot = NULL; #endif assert(_rtld_objself.needed == NULL); +#ifndef __mips__ /* no relocation for mips */ assert(!_rtld_objself.textrel); +#endif /* Set up the _rtld_objlist pointer, so that rtld symbols can be found. */ _rtld_objlist = &_rtld_objself; @@ -252,8 +259,10 @@ _rtld( #ifdef RTLD_DEBUG xprintf("_ctype_ is %p\n", _ctype_); #endif +#ifdef DEBUG if (aux_info[AUX_debug] != NULL) /* Set debugging level */ debug = aux_info[AUX_debug]->au_v; +#endif __progname = _rtld_objself.path; environ = env; @@ -264,9 +273,11 @@ _rtld( if (ld_bind_now != NULL && *ld_bind_now != '\0') bind_now = true; if (_rtld_trust) { +#ifdef DEBUG const char *ld_debug = getenv("LD_DEBUG"); if (ld_debug != NULL && *ld_debug != '\0') debug = 1; +#endif _rtld_add_paths(&_rtld_paths, getenv("LD_LIBRARY_PATH")); } @@ -543,6 +554,10 @@ _rtld_linkmap_add( obj->linkmap.l_name = obj->path; obj->linkmap.l_addr = obj->mapbase; obj->linkmap.l_ld = obj->dynamic; +#ifdef __mips__ + /* GDB needs load offset on MIPS to use the symbols */ + obj->linkmap.l_offs = obj->relocbase; +#endif if (_rtld_debug.r_map == NULL) { _rtld_debug.r_map = l; @@ -571,4 +586,3 @@ _rtld_linkmap_delete( if ((l->l_prev->l_next = l->l_next) != NULL) l->l_next->l_prev = l->l_prev; } - diff --git a/libexec/ld.elf_so/rtld.h b/libexec/ld.elf_so/rtld.h index a16a2f8d9592..3a02f13a73cb 100644 --- a/libexec/ld.elf_so/rtld.h +++ b/libexec/ld.elf_so/rtld.h @@ -1,4 +1,4 @@ -/* $NetBSD: rtld.h,v 1.3 1997/02/14 22:30:25 cgd Exp $ */ +/* $NetBSD: rtld.h,v 1.4 1998/03/25 04:13:02 mhitch Exp $ */ /* * Copyright 1996 John D. Polstra. @@ -122,6 +122,11 @@ typedef struct Struct_Obj_Entry { const Elf_Sym *symtab; /* Symbol table */ const char *strtab; /* String table */ unsigned long strsize; /* Size in bytes of string table */ +#if defined(__mips__) + Elf_Word local_gotno; /* Number of local GOT entries */ + Elf_Word symtabno; /* Number of dynamic symbols */ + Elf_Word gotsym; /* First dynamic symbol in GOT */ +#endif const Elf_Word *buckets; /* Hash table buckets array */ unsigned long nbuckets; /* Number of buckets */ @@ -208,4 +213,10 @@ extern const Elf_Sym *_rtld_find_symdef(const Obj_Entry *, Elf_Word, /* map_object.c */ extern Obj_Entry *_rtld_map_object(const char *, int); +#if defined(__mips__) +/* mips_reloc.c */ +extern void _rtld_relocate_mips_got(Obj_Entry *); +extern caddr_t _rtld_bind_mips (Elf_Word, Elf_Addr, Elf_Addr, Elf_Addr); +#endif + #endif /* } */ diff --git a/libexec/ld.elf_so/symbol.c b/libexec/ld.elf_so/symbol.c index e3bc4c0706d2..adbcf583ff38 100644 --- a/libexec/ld.elf_so/symbol.c +++ b/libexec/ld.elf_so/symbol.c @@ -1,4 +1,4 @@ -/* $NetBSD: symbol.c,v 1.1 1996/12/16 20:38:06 cgd Exp $ */ +/* $NetBSD: symbol.c,v 1.2 1998/03/25 04:13:02 mhitch Exp $ */ /* * Copyright 1996 John D. Polstra. @@ -102,8 +102,12 @@ _rtld_symlook_obj( #endif if (strcmp(name, strp) == 0) { if (symp->st_shndx != Elf_eshn_undefined +#if !defined(__mips__) /* Following doesn't work on MIPS? mhitch */ || (!in_plt && symp->st_value != 0 && ELF_SYM_TYPE(symp->st_info) == Elf_estt_func)) { +#else + ) { +#endif return symp; } }