freebsd-dev/libexec/rtld-elf/amd64/rtld_start.S
Ed Maste ebf8934652 rtld: do not rely on a populated GOT on amd64
On rela architectures GNU BFD ld and gold store the relocation addend
in GOT entries (in addition to the relocation's r_addend field).
rtld previously relied on this to access its own _DYNAMIC symbol in
order to apply its own relocations.

However, recording addends in the GOT is not specified by the ABI,
and some versions of LLVM's LLD linker leave the GOT uninitialized on
rela architectures.

BFD ld does not populate the GOT on sparc64, and sparc64 rtld has a
machine-dependent rtld_dynamic_addr() function that returns the
_DYNAMIC address. Use the same approach on amd64, obtaining the %rip-
relative _DYNAMIC address following a suggestion from Rafael Espíndola.

Architectures other than amd64 should be addressed in future work.

PR:		214972
Reviewed by:	kib
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D9180
2017-01-16 14:49:29 +00:00

172 lines
5.2 KiB
ArmAsm

/*-
* Copyright 1996-1998 John D. Polstra.
* 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.
*
* 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.
*
* $FreeBSD$
*/
.text
.align 4
.globl .rtld_start
.type .rtld_start,@function
.rtld_start:
xorq %rbp,%rbp # Clear frame pointer for good form
subq $24,%rsp # A place to store exit procedure addr
movq %rdi,%r12
movq %rsp,%rsi # save address of exit proc
movq %rsp,%rdx # construct address of obj_main
addq $8,%rdx
call _rtld # Call rtld(sp); returns entry point
popq %rsi # Get exit procedure address
movq %r12,%rdi # *ap
/*
* At this point, %rax contains the entry point of the main program, and
* %rdx contains a pointer to a termination function that should be
* registered with atexit(). (crt1.o registers it.)
*/
.globl .rtld_goto_main
.rtld_goto_main: # This symbol exists just to make debugging easier.
jmp *%rax # Enter main program
/*
* Binder entry point. Control is transferred to here by code in the PLT.
* On entry, there are two arguments on the stack. In ascending address
* order, they are (1) "obj", a pointer to the calling object's Obj_Entry,
* and (2) "reloff", the byte offset of the appropriate relocation entry
* in the PLT relocation table.
*
* We are careful to preserve all registers, even the caller-save
* registers. That is because this code may be invoked by low-level
* assembly-language code that is not ABI-compliant.
*
* Stack map:
* reloff 0x60
* obj 0x58
* spare 0x50
* rflags 0x48
* rax 0x40
* rdx 0x38
* rcx 0x30
* rsi 0x28
* rdi 0x20
* r8 0x18
* r9 0x10
* r10 0x8
* r11 0x0
*/
.align 4
.globl _rtld_bind_start
.type _rtld_bind_start,@function
_rtld_bind_start:
.cfi_startproc
.cfi_adjust_cfa_offset 16
subq $8,%rsp
.cfi_adjust_cfa_offset 8
pushfq # Save rflags
.cfi_adjust_cfa_offset 8
pushq %rax # Save %rax
.cfi_adjust_cfa_offset 8
.cfi_offset %rax,-32
pushq %rdx # Save %rdx
.cfi_adjust_cfa_offset 8
.cfi_offset %rdx,-40
pushq %rcx # Save %rcx
.cfi_adjust_cfa_offset 8
.cfi_offset %rcx,-48
pushq %rsi # Save %rsi
.cfi_adjust_cfa_offset 8
.cfi_offset %rsi,-56
pushq %rdi # Save %rdi
.cfi_adjust_cfa_offset 8
.cfi_offset %rdi,-64
pushq %r8 # Save %r8
.cfi_adjust_cfa_offset 8
.cfi_offset %r8,-72
pushq %r9 # Save %r9
.cfi_adjust_cfa_offset 8
.cfi_offset %r9,-80
pushq %r10 # Save %r10
.cfi_adjust_cfa_offset 8
.cfi_offset %r10,-88
pushq %r11 # Save %r11
.cfi_adjust_cfa_offset 8
.cfi_offset %r11,-96
movq 0x58(%rsp),%rdi # Fetch obj argument
movq 0x60(%rsp),%rsi # Fetch reloff argument
leaq (%rsi,%rsi,2),%rsi # multiply by 3
leaq (,%rsi,8),%rsi # now 8, for 24 (sizeof Elf_Rela)
call _rtld_bind # Transfer control to the binder
/* Now %rax contains the entry point of the function being called. */
movq %rax,0x60(%rsp) # Store target over reloff argument
popq %r11 # Restore %r11
.cfi_adjust_cfa_offset -8
.cfi_restore %r11
popq %r10 # Restore %r10
.cfi_adjust_cfa_offset -8
.cfi_restore %r10
popq %r9 # Restore %r9
.cfi_adjust_cfa_offset -8
.cfi_restore %r9
popq %r8 # Restore %r8
.cfi_adjust_cfa_offset -8
.cfi_restore %r8
popq %rdi # Restore %rdi
.cfi_adjust_cfa_offset -8
.cfi_restore %rdi
popq %rsi # Restore %rsi
.cfi_adjust_cfa_offset -8
.cfi_restore %rsi
popq %rcx # Restore %rcx
.cfi_adjust_cfa_offset -8
.cfi_restore %rcx
popq %rdx # Restore %rdx
.cfi_adjust_cfa_offset -8
.cfi_restore %rdx
popq %rax # Restore %rax
.cfi_adjust_cfa_offset -8
.cfi_restore %rax
popfq # Restore rflags
.cfi_adjust_cfa_offset -8
leaq 16(%rsp),%rsp # Discard spare, obj, do not change rflags
ret # "Return" to target address
.cfi_endproc
.size _rtld_bind_start, . - _rtld_bind_start
.align 4
.globl rtld_dynamic_addr
.type rtld_dynamic_addr,@function
rtld_dynamic_addr:
.cfi_startproc
.weak _DYNAMIC
.hidden _DYNAMIC
lea _DYNAMIC(%rip),%rax
ret
.cfi_endproc
.size rtld_dynamic_addr, . - rtld_dynamic_addr
.section .note.GNU-stack,"",%progbits