/* $NetBSD: rtld_start.S,v 1.10 2009/12/14 00:41:19 matt Exp $ */ /* * Copyright 1997 Michael L. Hitch * Portions copyright 2002 Charles M. Hannum * 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 #if defined(__clang__) || (defined(__GNUC__) && __GNUC__ > 4) .cfi_sections .debug_frame #endif .globl _C_LABEL(_rtld_relocate_nonplt_self) .globl _C_LABEL(_rtld) #define PTR_SIZE (1< 1*PTR_SIZE(sp) for atexit */ /* -> 2*PTR_SIZE(sp) for obj_main */ move s0, a0 /* save stack pointer from a0 */ move s3, a3 /* save ps_strings pointer */ PTR_LA a1, 1f bal 1f PTR_LA t0, _C_LABEL(_rtld_relocate_nonplt_self) 1: PTR_SUBU a1, ra, a1 /* relocbase */ PTR_LA a0, _DYNAMIC PTR_ADDU t9, a1, t0 jalr t9 /* _rtld_relocate_nonplt_self(dynp, relocabase) */ PTR_ADDU a0, a1, a0 /* &_DYNAMIC */ move a0, s0 /* sp */ PTR_ADDU a1, sp, 2*PTR_SIZE /* &our atexit function */ PTR_ADDU a2, sp, 3*PTR_SIZE /* obj_main entry */ PTR_SUBU sp, 4*SZREG /* ABI requires to reserve memory for 4 regs */ PTR_LA t9, _C_LABEL(_rtld) jalr t9 /* v0 = _rtld(sp, cleanup, objp) */ nop PTR_ADDU sp, 4*SZREG PTR_L a1, 2*PTR_SIZE(sp) /* our atexit function */ PTR_L a2, 3*PTR_SIZE(sp) /* obj_main entry */ PTR_ADDU sp, 4*PTR_SIZE /* readjust stack */ move a0, s0 /* stack pointer */ move t9, v0 PTR_SUBU sp, 4*SZREG /* ABI requires to reserve memory for 4 regs */ move ra,t9 /* RA == PC signals backtrace routine to stop */ j t9 /* _start(sp, cleanup, obj); */ move a3, s3 /* restore ps_strings */ END(rtld_start) #define XCALLFRAME_SIZ (12*SZREG) #define XCALLFRAME_RA (10*SZREG) #define XCALLFRAME_GP (9*SZREG) #define XCALLFRAME_S0 (8*SZREG) #define XCALLFRAME_A3 (7*SZREG) #define XCALLFRAME_A2 (6*SZREG) #define XCALLFRAME_A1 (5*SZREG) #define XCALLFRAME_A0 (4*SZREG) #if defined(__mips_n32) || defined(__mips_n64) #define XCALLFRAME_A7 (3*SZREG) #define XCALLFRAME_A6 (2*SZREG) #define XCALLFRAME_A5 (1*SZREG) #define XCALLFRAME_A4 (0*SZREG) #endif /* * Trampoline for "old" PLT stubs which use .got entries. */ .globl _rtld_bind_start .ent _rtld_bind_start _rtld_bind_start: .frame sp, XCALLFRAME_SIZ, $15 .cfi_startproc simple .cfi_def_cfa sp, 0 .cfi_register ra, $15 move v1, gp /* save old GP */ #if defined(__mips_o32) || defined(__mips_o64) PTR_ADDU t9, 8 /* modify T9 to point at .cpload */ #endif SETUP_GP PTR_SUBU sp, XCALLFRAME_SIZ /* save arguments and sp value in stack */ .cfi_def_cfa_offset XCALLFRAME_SIZ SETUP_GP64(XCALLFRAME_GP, _rtld_bind_start) SAVE_GP(XCALLFRAME_GP) #if defined(__mips_n32) || defined(__mips_n64) REG_S a4, XCALLFRAME_A4(sp) .cfi_rel_offset a4, XCALLFRAME_A4 REG_S a5, XCALLFRAME_A5(sp) .cfi_rel_offset a5, XCALLFRAME_A5 REG_S a6, XCALLFRAME_A6(sp) .cfi_rel_offset a6, XCALLFRAME_A6 REG_S a7, XCALLFRAME_A7(sp) .cfi_rel_offset a7, XCALLFRAME_A7 #endif REG_S a0, XCALLFRAME_A0(sp) .cfi_rel_offset a0, XCALLFRAME_A0 REG_S a1, XCALLFRAME_A1(sp) .cfi_rel_offset a1, XCALLFRAME_A1 REG_S a2, XCALLFRAME_A2(sp) .cfi_rel_offset a2, XCALLFRAME_A2 REG_S a3, XCALLFRAME_A3(sp) .cfi_rel_offset a3, XCALLFRAME_A3 REG_S $15, XCALLFRAME_RA(sp) /* ra is in t7/t3 */ .cfi_rel_offset ra, XCALLFRAME_RA REG_S s0, XCALLFRAME_S0(sp) .cfi_rel_offset s0, XCALLFRAME_S0 move s0, sp move a0, v1 /* old GP */ PTR_SUBU a0, a0, 0x7ff0 /* The offset of $gp from the */ /* beginning of the .got section: */ /* $gp = .got + 0x7ff0, so */ /* .got = $gp - 0x7ff0 */ /* Simple math as you can see. */ #if defined(__mips_n64) ld a0, 8(a0) /* object = pltgot[1] */ and a0, a0, 0x7fffffffffffffff #else lw a0, 4(a0) /* object = pltgot[1] & 0x7fffffff */ and a0, a0, 0x7fffffff #endif move a1, t8 /* symbol index */ PTR_LA t9, _C_LABEL(_mips_rtld_bind) jalr t9 nop move sp, s0 REG_L ra, XCALLFRAME_RA(sp) .cfi_restore ra REG_L s0, XCALLFRAME_S0(sp) .cfi_restore s0 REG_L a0, XCALLFRAME_A0(sp) .cfi_restore a0 REG_L a1, XCALLFRAME_A1(sp) .cfi_restore a1 REG_L a2, XCALLFRAME_A2(sp) .cfi_restore a2 REG_L a3, XCALLFRAME_A3(sp) .cfi_restore a3 #if defined(__mips_n32) || defined(__mips_n64) REG_L a4, XCALLFRAME_A4(sp) .cfi_restore a4 REG_L a5, XCALLFRAME_A5(sp) .cfi_restore a5 REG_L a6, XCALLFRAME_A6(sp) .cfi_restore a6 REG_L a7, XCALLFRAME_A7(sp) .cfi_restore a7 #endif RESTORE_GP64 PTR_ADDU sp, XCALLFRAME_SIZ move t9, v0 jr t9 nop .cfi_endproc END(_rtld_bind_start) /* * Trampoline for PLT stubs using .pltrel entries and .got.plt. */ .globl _rtld_pltbind_start .ent _rtld_pltbind_start _rtld_pltbind_start: .frame sp, XCALLFRAME_SIZ, $15 .cfi_startproc simple .cfi_def_cfa sp, 0 .cfi_register ra, $15 #if defined(__mips_o32) move v1, gp /* save pointer to .got.plt */ #else move v1, t2 /* save pointer to .got.plt */ #endif #if defined(__mips_o32) || defined(__mips_o64) PTR_ADDU t9, 8 /* modify T9 to point at .cpload */ #endif SETUP_GP PTR_SUBU sp, XCALLFRAME_SIZ /* save arguments and sp value in stack */ .cfi_def_cfa_offset XCALLFRAME_SIZ SETUP_GP64(XCALLFRAME_GP, _rtld_pltbind_start) SAVE_GP(XCALLFRAME_GP) #if defined(__mips_n32) || defined(__mips_n64) REG_S a4, XCALLFRAME_A4(sp) .cfi_rel_offset a4, XCALLFRAME_A4 REG_S a5, XCALLFRAME_A5(sp) .cfi_rel_offset a5, XCALLFRAME_A5 REG_S a6, XCALLFRAME_A6(sp) .cfi_rel_offset a6, XCALLFRAME_A6 REG_S a7, XCALLFRAME_A7(sp) .cfi_rel_offset a7, XCALLFRAME_A7 #endif REG_S a0, XCALLFRAME_A0(sp) .cfi_rel_offset a0, XCALLFRAME_A0 REG_S a1, XCALLFRAME_A1(sp) .cfi_rel_offset a1, XCALLFRAME_A1 REG_S a2, XCALLFRAME_A2(sp) .cfi_rel_offset a2, XCALLFRAME_A2 REG_S a3, XCALLFRAME_A3(sp) .cfi_rel_offset a3, XCALLFRAME_A3 REG_S $15, XCALLFRAME_RA(sp) /* ra is in t7/t3 */ .cfi_rel_offset ra, XCALLFRAME_RA REG_S s0, XCALLFRAME_S0(sp) .cfi_rel_offset s0, XCALLFRAME_S0 move s0, sp move a0, v1 /* .got.plt */ #if defined(__mips_n64) ld a0, 8(a0) /* object = .got.plt[1] */ sll a1, t8, 4 /* PLT entry index to .rel.plt offset */ #else lw a0, 4(a0) /* object = .got.plt[1] */ sll a1, t8, 3 /* PLT entry index to .rel.plt offset */ #endif PTR_LA t9, _C_LABEL(_rtld_bind) jalr t9 nop move sp, s0 REG_L ra, XCALLFRAME_RA(sp) .cfi_restore ra REG_L s0, XCALLFRAME_S0(sp) .cfi_restore s0 REG_L a0, XCALLFRAME_A0(sp) .cfi_restore a0 REG_L a1, XCALLFRAME_A1(sp) .cfi_restore a1 REG_L a2, XCALLFRAME_A2(sp) .cfi_restore a2 REG_L a3, XCALLFRAME_A3(sp) .cfi_restore a3 #if defined(__mips_n32) || defined(__mips_n64) REG_L a4, XCALLFRAME_A4(sp) .cfi_restore a4 REG_L a5, XCALLFRAME_A5(sp) .cfi_restore a5 REG_L a6, XCALLFRAME_A6(sp) .cfi_restore a6 REG_L a7, XCALLFRAME_A7(sp) .cfi_restore a7 #endif RESTORE_GP64 PTR_ADDU sp, XCALLFRAME_SIZ move t9, v0 jr t9 nop .cfi_endproc END(_rtld_pltbind_start)