switch to netbsd csu
. file- and functionality-compatible with previous situation
(FreeBSD csu) (with a crt1.o -> crt0.o symlink in /usr/lib)
. harmonizes source with netbsd
. harmonizes linker invocation (e.g. clang) with netbsd
. helpful to get some arm code in there for the arm port project
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
# $NetBSD: Makefile.inc,v 1.11 2009/10/22 21:56:13 skrll Exp $
|
||||
|
||||
SRCS+= rtld_start.S ppc_reloc.c
|
||||
|
||||
# XXX Should not be in CPPFLAGS!
|
||||
CPPFLAGS+= -fpic -msoft-float
|
||||
|
||||
CPPFLAGS+= -DELFSIZE=32
|
||||
|
||||
LDFLAGS+= -Wl,-e,_rtld_start
|
||||
LDFLAGS+= -Wl,--script,${.CURDIR}/arch/powerpc/ld.so.script
|
||||
@@ -0,0 +1,271 @@
|
||||
OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc",
|
||||
"elf32-powerpc")
|
||||
OUTPUT_ARCH(powerpc)
|
||||
ENTRY(_start)
|
||||
/* Do we need any of these for elf?
|
||||
__DYNAMIC = 0; */
|
||||
PROVIDE (__stack = 0); PROVIDE (___stack = 0);
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
. = 0 + SIZEOF_HEADERS;
|
||||
.hash : { *(.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
.rel.init : { *(.rel.init) }
|
||||
.rela.init : { *(.rela.init) }
|
||||
.rel.text :
|
||||
{
|
||||
*(.rel.text)
|
||||
*(.rel.text.*)
|
||||
*(.rel.gnu.linkonce.t.*)
|
||||
}
|
||||
.rela.text :
|
||||
{
|
||||
*(.rela.text)
|
||||
*(.rela.text.*)
|
||||
*(.rela.gnu.linkonce.t.*)
|
||||
}
|
||||
.rel.fini : { *(.rel.fini) }
|
||||
.rela.fini : { *(.rela.fini) }
|
||||
.rel.rodata :
|
||||
{
|
||||
*(.rel.rodata)
|
||||
*(.rel.rodata.*)
|
||||
*(.rel.gnu.linkonce.r.*)
|
||||
}
|
||||
.rela.rodata :
|
||||
{
|
||||
*(.rela.rodata)
|
||||
*(.rela.rodata.*)
|
||||
*(.rela.gnu.linkonce.r.*)
|
||||
}
|
||||
.rel.data :
|
||||
{
|
||||
*(.rel.data)
|
||||
*(.rel.data.*)
|
||||
*(.rel.gnu.linkonce.d.*)
|
||||
}
|
||||
.rela.data :
|
||||
{
|
||||
*(.rela.data)
|
||||
*(.rela.data.*)
|
||||
*(.rela.gnu.linkonce.d.*)
|
||||
}
|
||||
.rel.ctors : { *(.rel.ctors) }
|
||||
.rela.ctors : { *(.rela.ctors) }
|
||||
.rel.dtors : { *(.rel.dtors) }
|
||||
.rela.dtors : { *(.rela.dtors) }
|
||||
.rel.got : { *(.rel.got) }
|
||||
.rela.got : { *(.rela.got) }
|
||||
.rel.sdata :
|
||||
{
|
||||
*(.rel.sdata)
|
||||
*(.rel.sdata.*)
|
||||
*(.rel.gnu.linkonce.s.*)
|
||||
}
|
||||
.rela.sdata :
|
||||
{
|
||||
*(.rela.sdata)
|
||||
*(.rela.sdata.*)
|
||||
*(.rela.gnu.linkonce.s.*)
|
||||
}
|
||||
.rel.sbss :
|
||||
{
|
||||
*(.rel.sbss)
|
||||
*(.rel.sbss.*)
|
||||
*(.rel.gnu.linkonce.sb.*)
|
||||
}
|
||||
.rela.sbss :
|
||||
{
|
||||
*(.rela.sbss)
|
||||
*(.rela.sbss.*)
|
||||
*(.rel.gnu.linkonce.sb.*)
|
||||
}
|
||||
.rel.sdata2 :
|
||||
{
|
||||
*(.rel.sdata2)
|
||||
*(.rel.sdata2.*)
|
||||
*(.rel.gnu.linkonce.s2.*)
|
||||
}
|
||||
.rela.sdata2 :
|
||||
{
|
||||
*(.rela.sdata2)
|
||||
*(.rela.sdata2.*)
|
||||
*(.rela.gnu.linkonce.s2.*)
|
||||
}
|
||||
.rel.sbss2 :
|
||||
{
|
||||
*(.rel.sbss2)
|
||||
*(.rel.sbss2.*)
|
||||
*(.rel.gnu.linkonce.sb2.*)
|
||||
}
|
||||
.rela.sbss2 :
|
||||
{
|
||||
*(.rela.sbss2)
|
||||
*(.rela.sbss2.*)
|
||||
*(.rela.gnu.linkonce.sb2.*)
|
||||
}
|
||||
.rel.bss :
|
||||
{
|
||||
*(.rel.bss)
|
||||
*(.rel.bss.*)
|
||||
*(.rel.gnu.linkonce.b.*)
|
||||
}
|
||||
.rela.bss :
|
||||
{
|
||||
*(.rela.bss)
|
||||
*(.rela.bss.*)
|
||||
*(.rela.gnu.linkonce.b.*)
|
||||
}
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.init :
|
||||
{
|
||||
KEEP (*(.init))
|
||||
} =0
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
*(.stub)
|
||||
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||
*(.gnu.warning)
|
||||
*(.gnu.linkonce.t.*)
|
||||
} =0
|
||||
.fini :
|
||||
{
|
||||
KEEP (*(.fini))
|
||||
} =0
|
||||
PROVIDE (__etext = .);
|
||||
PROVIDE (_etext = .);
|
||||
PROVIDE (etext = .);
|
||||
.rodata : { *(.rodata) *(.rodata.*) *(.gnu.linkonce.r.*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
/* Adjust the address for the data segment. We want to adjust up to
|
||||
the same address within the page on the next page up. */
|
||||
. = ALIGN(8);
|
||||
.data :
|
||||
{
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
*(.gnu.linkonce.d.*)
|
||||
SORT(CONSTRUCTORS)
|
||||
}
|
||||
.data1 : { *(.data1) }
|
||||
.eh_frame : { KEEP (*(.eh_frame)) }
|
||||
.gcc_except_table : { *(.gcc_except_table) }
|
||||
.fixup : { *(.fixup) }
|
||||
.got1 : { *(.got1) }
|
||||
.got2 : { *(.got2) }
|
||||
.ctors :
|
||||
{
|
||||
/* gcc uses crtbegin.o to find the start of
|
||||
the constructors, so we make sure it is
|
||||
first. Because this is a wildcard, it
|
||||
doesn't matter if the user does not
|
||||
actually link against crtbegin.o; the
|
||||
linker won't look for a file to match a
|
||||
wildcard. The wildcard also means that it
|
||||
doesn't matter which directory crtbegin.o
|
||||
is in. */
|
||||
KEEP (*crtbegin.o(.ctors))
|
||||
/* We don't want to include the .ctor section from
|
||||
from the crtend.o file until after the sorted ctors.
|
||||
The .ctor section from the crtend file contains the
|
||||
end of ctors marker and it must be last */
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
KEEP (*crtbegin.o(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
|
||||
KEEP (*(SORT(.dtors.*)))
|
||||
KEEP (*(.dtors))
|
||||
}
|
||||
.got : { *(.got.plt) *(.got) }
|
||||
PROVIDE (_GOT_END_ = .);
|
||||
.sdata2 : { *(.sdata2) *(.sdata2.*) *(.gnu.linkonce.s2.*) }
|
||||
.sbss2 : { *(.sbss2) *(.sbss2.*) *(.gnu.linkonce.sb2.*) }
|
||||
.dynamic : { *(.dynamic) }
|
||||
/* 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)
|
||||
*(.sdata.*)
|
||||
*(.gnu.linkonce.s.*)
|
||||
}
|
||||
_edata = .;
|
||||
PROVIDE (edata = .);
|
||||
__bss_start = .;
|
||||
.sbss :
|
||||
{
|
||||
PROVIDE (__sbss_start = .);
|
||||
PROVIDE (___sbss_start = .);
|
||||
*(.dynsbss)
|
||||
*(.sbss)
|
||||
*(.sbss.*)
|
||||
*(.gnu.linkonce.sb.*)
|
||||
*(.scommon)
|
||||
PROVIDE (__sbss_end = .);
|
||||
PROVIDE (___sbss_end = .);
|
||||
}
|
||||
.plt : { *(.plt) }
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss)
|
||||
*(.bss.*)
|
||||
*(.gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
/* Align here to ensure that the .bss section occupies space up to
|
||||
_end. Align after .bss to ensure correct alignment even if the
|
||||
.bss section disappears because there are no input sections. */
|
||||
. = ALIGN(8);
|
||||
}
|
||||
. = ALIGN(8);
|
||||
_end = .;
|
||||
__end = .;
|
||||
PROVIDE (end = .);
|
||||
/* Stabs debugging sections. */
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
/* 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) *(.gnu.linkonce.wi.*) }
|
||||
.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 . */
|
||||
}
|
||||
@@ -0,0 +1,370 @@
|
||||
/* $NetBSD: ppc_reloc.c,v 1.46 2011/01/16 01:22:29 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (C) 1998 Tsubai Masanari
|
||||
* Portions copyright 2002 Charles M. Hannum <root@ihack.net>
|
||||
* 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 <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
__RCSID("$NetBSD: ppc_reloc.c,v 1.46 2011/01/16 01:22:29 matt Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <machine/cpu.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "rtld.h"
|
||||
|
||||
void _rtld_powerpc_pltcall(Elf_Word);
|
||||
void _rtld_powerpc_pltresolve(Elf_Word, Elf_Word);
|
||||
|
||||
#define ha(x) ((((u_int32_t)(x) & 0x8000) ? \
|
||||
((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16)
|
||||
#define l(x) ((u_int32_t)(x) & 0xffff)
|
||||
|
||||
void _rtld_bind_bssplt_start(void);
|
||||
void _rtld_bind_secureplt_start(void);
|
||||
void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
|
||||
caddr_t _rtld_bind(const Obj_Entry *, Elf_Word);
|
||||
static int _rtld_relocate_plt_object(const Obj_Entry *,
|
||||
const Elf_Rela *, int, Elf_Addr *);
|
||||
|
||||
/*
|
||||
* The PPC PLT format consists of three sections:
|
||||
* (1) The "pltcall" and "pltresolve" glue code. This is always 18 words.
|
||||
* (2) The code part of the PLT entries. There are 2 words per entry for
|
||||
* up to 8192 entries, then 4 words per entry for any additional entries.
|
||||
* (3) The data part of the PLT entries, comprising a jump table.
|
||||
* This section is half the size of the second section (ie. 1 or 2 words
|
||||
* per entry).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Setup the plt glue routines (for bss-plt).
|
||||
*/
|
||||
#define PLTCALL_SIZE 20
|
||||
#define PLTRESOLVE_SIZE 24
|
||||
|
||||
void
|
||||
_rtld_setup_pltgot(const Obj_Entry *obj)
|
||||
{
|
||||
/*
|
||||
* Secure-PLT is much more sane.
|
||||
*/
|
||||
if (obj->gotptr != NULL) {
|
||||
obj->gotptr[1] = (Elf_Addr) _rtld_bind_secureplt_start;
|
||||
obj->gotptr[2] = (Elf_Addr) obj;
|
||||
} else {
|
||||
Elf_Word *pltcall, *pltresolve;
|
||||
Elf_Word *jmptab;
|
||||
int N = obj->pltrelalim - obj->pltrela;
|
||||
|
||||
/* Entries beyond 8192 take twice as much space. */
|
||||
if (N > 8192)
|
||||
N += N-8192;
|
||||
|
||||
pltcall = obj->pltgot;
|
||||
jmptab = pltcall + 18 + N * 2;
|
||||
|
||||
memcpy(pltcall, _rtld_powerpc_pltcall, PLTCALL_SIZE);
|
||||
pltcall[1] |= ha(jmptab);
|
||||
pltcall[2] |= l(jmptab);
|
||||
|
||||
pltresolve = obj->pltgot + 8;
|
||||
|
||||
memcpy(pltresolve, _rtld_powerpc_pltresolve, PLTRESOLVE_SIZE);
|
||||
pltresolve[0] |= ha(_rtld_bind_bssplt_start);
|
||||
pltresolve[1] |= l(_rtld_bind_bssplt_start);
|
||||
pltresolve[3] |= ha(obj);
|
||||
pltresolve[4] |= l(obj);
|
||||
|
||||
/*
|
||||
* Invalidate the icache for only the code part of the PLT
|
||||
* (and not the jump table at the end).
|
||||
*/
|
||||
__syncicache(pltcall, (char *)jmptab - (char *)pltcall);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
|
||||
{
|
||||
const Elf_Rela *rela = 0, *relalim;
|
||||
Elf_Addr relasz = 0;
|
||||
Elf_Addr *where;
|
||||
|
||||
for (; dynp->d_tag != DT_NULL; dynp++) {
|
||||
switch (dynp->d_tag) {
|
||||
case DT_RELA:
|
||||
rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr);
|
||||
break;
|
||||
case DT_RELASZ:
|
||||
relasz = dynp->d_un.d_val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
relalim = (const Elf_Rela *)((const uint8_t *)rela + relasz);
|
||||
for (; rela < relalim; rela++) {
|
||||
where = (Elf_Addr *)(relocbase + rela->r_offset);
|
||||
*where = (Elf_Addr)(relocbase + rela->r_addend);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
_rtld_relocate_nonplt_objects(Obj_Entry *obj)
|
||||
{
|
||||
const Elf_Rela *rela;
|
||||
|
||||
for (rela = obj->rela; rela < obj->relalim; rela++) {
|
||||
Elf_Addr *where;
|
||||
const Elf_Sym *def;
|
||||
const Obj_Entry *defobj;
|
||||
Elf_Addr tmp;
|
||||
unsigned long symnum;
|
||||
|
||||
where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
|
||||
symnum = ELF_R_SYM(rela->r_info);
|
||||
|
||||
switch (ELF_R_TYPE(rela->r_info)) {
|
||||
#if 1 /* XXX Should not be necessary. */
|
||||
case R_TYPE(JMP_SLOT):
|
||||
#endif
|
||||
case R_TYPE(NONE):
|
||||
break;
|
||||
|
||||
case R_TYPE(32): /* word32 S + A */
|
||||
case R_TYPE(GLOB_DAT): /* word32 S + A */
|
||||
def = _rtld_find_symdef(symnum, obj, &defobj, false);
|
||||
if (def == NULL)
|
||||
return -1;
|
||||
|
||||
tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
|
||||
rela->r_addend);
|
||||
if (*where != tmp)
|
||||
*where = tmp;
|
||||
rdbg(("32/GLOB_DAT %s in %s --> %p in %s",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)*where, defobj->path));
|
||||
break;
|
||||
|
||||
case R_TYPE(RELATIVE): /* word32 B + A */
|
||||
*where = (Elf_Addr)(obj->relocbase + rela->r_addend);
|
||||
rdbg(("RELATIVE in %s --> %p", obj->path,
|
||||
(void *)*where));
|
||||
break;
|
||||
|
||||
case R_TYPE(COPY):
|
||||
/*
|
||||
* These are deferred until all other relocations have
|
||||
* been done. All we do here is make sure that the
|
||||
* COPY relocation is not in a shared library. They
|
||||
* are allowed only in executable files.
|
||||
*/
|
||||
if (obj->isdynamic) {
|
||||
_rtld_error(
|
||||
"%s: Unexpected R_COPY relocation in shared library",
|
||||
obj->path);
|
||||
return -1;
|
||||
}
|
||||
rdbg(("COPY (avoid in main)"));
|
||||
break;
|
||||
|
||||
default:
|
||||
rdbg(("sym = %lu, type = %lu, offset = %p, "
|
||||
"addend = %p, contents = %p, symbol = %s",
|
||||
symnum, (u_long)ELF_R_TYPE(rela->r_info),
|
||||
(void *)rela->r_offset, (void *)rela->r_addend,
|
||||
(void *)*where,
|
||||
obj->strtab + obj->symtab[symnum].st_name));
|
||||
_rtld_error("%s: Unsupported relocation type %ld "
|
||||
"in non-PLT relocations",
|
||||
obj->path, (u_long) ELF_R_TYPE(rela->r_info));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_rtld_relocate_plt_lazy(const Obj_Entry *obj)
|
||||
{
|
||||
Elf_Addr * const pltresolve = obj->pltgot + 8;
|
||||
const Elf_Rela *rela;
|
||||
int reloff;
|
||||
|
||||
for (rela = obj->pltrela, reloff = 0;
|
||||
rela < obj->pltrelalim;
|
||||
rela++, reloff++) {
|
||||
Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
|
||||
|
||||
assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT));
|
||||
|
||||
if (obj->gotptr != NULL) {
|
||||
/*
|
||||
* For now, simply treat then as relative.
|
||||
*/
|
||||
*where += (Elf_Addr)obj->relocbase;
|
||||
} else {
|
||||
int distance;
|
||||
|
||||
if (reloff < 32768) {
|
||||
/* li r11,reloff */
|
||||
*where++ = 0x39600000 | reloff;
|
||||
} else {
|
||||
/* lis r11,ha(reloff) */
|
||||
/* addi r11,l(reloff) */
|
||||
*where++ = 0x3d600000 | ha(reloff);
|
||||
*where++ = 0x396b0000 | l(reloff);
|
||||
}
|
||||
/* b pltresolve */
|
||||
distance = (Elf_Addr)pltresolve - (Elf_Addr)where;
|
||||
*where++ = 0x48000000 | (distance & 0x03fffffc);
|
||||
|
||||
/*
|
||||
* Icache invalidation is not done for each entry here
|
||||
* because we sync the entire code part of the PLT once
|
||||
* in _rtld_setup_pltgot() after all the entries have been
|
||||
* initialized.
|
||||
*/
|
||||
/* __syncicache(where - 3, 12); */
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, int reloff, Elf_Addr *tp)
|
||||
{
|
||||
Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
|
||||
Elf_Addr value;
|
||||
const Elf_Sym *def;
|
||||
const Obj_Entry *defobj;
|
||||
int distance;
|
||||
unsigned long info = rela->r_info;
|
||||
|
||||
assert(ELF_R_TYPE(info) == R_TYPE(JMP_SLOT));
|
||||
|
||||
def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, tp != NULL);
|
||||
if (__predict_false(def == NULL))
|
||||
return -1;
|
||||
if (__predict_false(def == &_rtld_sym_zero))
|
||||
return 0;
|
||||
|
||||
value = (Elf_Addr)(defobj->relocbase + def->st_value);
|
||||
distance = value - (Elf_Addr)where;
|
||||
rdbg(("bind now/fixup in %s --> new=%p",
|
||||
defobj->strtab + def->st_name, (void *)value));
|
||||
|
||||
if (obj->gotptr != NULL) {
|
||||
/*
|
||||
* For Secure-PLT we simply replace the entry in GOT with the address
|
||||
* of the routine.
|
||||
*/
|
||||
assert(where >= (Elf_Word *)obj->pltgot);
|
||||
assert(where < (Elf_Word *)obj->pltgot + (obj->pltrelalim - obj->pltrela));
|
||||
*where = value;
|
||||
} else if (abs(distance) < 32*1024*1024) { /* inside 32MB? */
|
||||
/* b value # branch directly */
|
||||
*where = 0x48000000 | (distance & 0x03fffffc);
|
||||
__syncicache(where, 4);
|
||||
} else {
|
||||
Elf_Addr *pltcall, *jmptab;
|
||||
int N = obj->pltrelalim - obj->pltrela;
|
||||
|
||||
/* Entries beyond 8192 take twice as much space. */
|
||||
if (N > 8192)
|
||||
N += N-8192;
|
||||
|
||||
pltcall = obj->pltgot;
|
||||
jmptab = pltcall + 18 + N * 2;
|
||||
|
||||
jmptab[reloff] = value;
|
||||
|
||||
if (reloff < 32768) {
|
||||
/* li r11,reloff */
|
||||
*where++ = 0x39600000 | reloff;
|
||||
} else {
|
||||
#ifdef notyet
|
||||
/* lis r11,ha(value) */
|
||||
/* addi r11,l(value) */
|
||||
/* mtctr r11 */
|
||||
/* bctr */
|
||||
*where++ = 0x3d600000 | ha(value);
|
||||
*where++ = 0x396b0000 | l(value);
|
||||
*where++ = 0x7d6903a6;
|
||||
*where++ = 0x4e800420;
|
||||
#else
|
||||
/* lis r11,ha(reloff) */
|
||||
/* addi r11,l(reloff) */
|
||||
*where++ = 0x3d600000 | ha(reloff);
|
||||
*where++ = 0x396b0000 | l(reloff);
|
||||
#endif
|
||||
}
|
||||
/* b pltcall */
|
||||
distance = (Elf_Addr)pltcall - (Elf_Addr)where;
|
||||
*where++ = 0x48000000 | (distance & 0x03fffffc);
|
||||
__syncicache(where - 3, 12);
|
||||
}
|
||||
|
||||
if (tp)
|
||||
*tp = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
caddr_t
|
||||
_rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
|
||||
{
|
||||
const Elf_Rela *rela = (const void *)((const char *)obj->pltrela + reloff);
|
||||
Elf_Addr new_value;
|
||||
int err;
|
||||
|
||||
new_value = 0; /* XXX gcc */
|
||||
|
||||
err = _rtld_relocate_plt_object(obj, rela, reloff, &new_value);
|
||||
if (err)
|
||||
_rtld_die();
|
||||
|
||||
return (caddr_t)new_value;
|
||||
}
|
||||
|
||||
int
|
||||
_rtld_relocate_plt_objects(const Obj_Entry *obj)
|
||||
{
|
||||
const Elf_Rela *rela;
|
||||
int reloff;
|
||||
|
||||
for (rela = obj->pltrela, reloff = 0; rela < obj->pltrelalim; rela++, reloff++) {
|
||||
if (_rtld_relocate_plt_object(obj, rela, reloff, NULL) < 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/* $NetBSD: rtld_start.S,v 1.14 2011/01/16 01:22:29 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (C) 1998 Tsubai Masanari
|
||||
* Portions copyright 2002 Charles M. Hannum <root@ihack.net>
|
||||
* 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 <machine/asm.h>
|
||||
|
||||
.globl _rtld_start
|
||||
.globl _rtld
|
||||
|
||||
.text
|
||||
|
||||
_rtld_start:
|
||||
stwu %r1,-48(%r1)
|
||||
stw %r3,12(%r1) # argc
|
||||
stw %r4,16(%r1) # argv
|
||||
stw %r5,20(%r1) # envp
|
||||
/* stw %r6,24(%r1) # obj (always 0) */
|
||||
/* stw %r7,28(%r1) # cleanup (always 0) */
|
||||
stw %r8,32(%r1) # ps_strings
|
||||
|
||||
bcl 20,31,1f
|
||||
1: mflr %r30
|
||||
mr %r3,%r30 # save for _DYNAMIC
|
||||
addis %r30,%r30,_GLOBAL_OFFSET_TABLE_-1b@ha
|
||||
addi %r30,%r30,_GLOBAL_OFFSET_TABLE_-1b@l
|
||||
addis %r3,%r3,_DYNAMIC-1b@ha # get _DYNAMIC actual address
|
||||
addi %r3,%r3,_DYNAMIC-1b@l
|
||||
lwz %r28,0(%r30) # get base-relative &_DYNAMIC
|
||||
sub %r28,%r3,%r28 # r28 = relocbase
|
||||
mr %r4,%r28 # r4 = relocbase
|
||||
bl _rtld_relocate_nonplt_self
|
||||
|
||||
lwz %r3,16(%r1)
|
||||
addi %r3,%r3,-12 # sp = &argv[-3] /* XXX */
|
||||
mr %r4,%r28 # r4 = relocbase
|
||||
bl _rtld # _start = _rtld(sp, relocbase)
|
||||
mtlr %r3
|
||||
|
||||
lwz %r3,12(%r1) # argc
|
||||
lwz %r4,16(%r1) # argv
|
||||
lwz %r5,20(%r1) # envp
|
||||
lwz %r6,-8(%r4) # obj = sp[1] (== argv[-2])
|
||||
lwz %r7,-12(%r4) # cleanup = sp[0] (== argv[-3])
|
||||
lwz %r8,32(%r1) # ps_strings
|
||||
|
||||
addi %r1,%r1,48
|
||||
blrl # _start(argc, argv, envp, obj, cleanup, ps_strings)
|
||||
|
||||
li %r0,1 # _exit()
|
||||
sc
|
||||
|
||||
END(_rtld_start)
|
||||
|
||||
.globl _rtld_bind
|
||||
|
||||
/*
|
||||
* secure-plt expects %r11 to be the offset to the rela entry.
|
||||
* bss-plt expects %r11 to be index of the rela entry.
|
||||
* So for bss-plt, we multiply the index by 12 to get the offset.
|
||||
*/
|
||||
ENTRY_NOPROFILE(_rtld_bind_bssplt_start)
|
||||
slwi %r11,%r11,2
|
||||
add %r0,%r11,%r11
|
||||
add %r11,%r11,%r0
|
||||
ENTRY_NOPROFILE(_rtld_bind_secureplt_start)
|
||||
stwu %r1,-160(%r1)
|
||||
|
||||
stw %r0,20(%r1)
|
||||
mflr %r0
|
||||
stw %r0,16(%r1) # save lr
|
||||
mfcr %r0
|
||||
stw %r0,12(%r1) # save cr
|
||||
stmw %r3,24(%r1) # save r3-r31
|
||||
|
||||
mr %r3,%r12 # obj
|
||||
mr %r4,%r11 # reloff
|
||||
bl _rtld_bind # _rtld_bind(obj, reloff)
|
||||
mtctr %r3
|
||||
|
||||
lmw %r3,24(%r1) # load r3-r31
|
||||
lwz %r0,12(%r1) # restore cr
|
||||
mtcr %r0
|
||||
lwz %r0,16(%r1) # restore lr
|
||||
mtlr %r0
|
||||
lwz %r0,20(%r1)
|
||||
|
||||
addi %r1,%r1,160
|
||||
bctr
|
||||
END(_rtld_bind_start)
|
||||
|
||||
.globl _rtld_powerpc_pltcall
|
||||
.globl _rtld_powerpc_pltresolve
|
||||
|
||||
_rtld_powerpc_pltcall:
|
||||
slwi %r11,%r11,2
|
||||
addis %r11,%r11,0 # addis 11,11,jmptab@ha
|
||||
lwz %r11,0(%r11) # lwz 11,jmptab@l(11)
|
||||
mtctr %r11
|
||||
bctr
|
||||
|
||||
_rtld_powerpc_pltresolve:
|
||||
lis %r12,0 # lis 12,_rtld_bind_bssplt_start@ha
|
||||
addi %r12,%r12,0 # addi 12,12,_rtld_bind_bssplt_start@l
|
||||
mtctr %r12
|
||||
lis %r12,0 # lis 12,obj@ha
|
||||
addi %r12,%r12,0 # addi 12,12,obj@l
|
||||
bctr
|
||||
Reference in New Issue
Block a user