opnsense-src/libexec/rtld-elf/amd64/rtld_start.S
Dmitry Chagin 3bdf68086d rtld: Add a stop indicator to rtld_start to satisfy unwinders on x86_64
The right unwinding stop indicator should be CFI-undefined PC.
https://dwarfstd.org/doc/Dwarf3.pdf - page 118:
If a Return Address register is defined in the virtual unwind table,
and its rule is undefined (for example, by DW_CFA_undefined), then
there is no return address and no call address, and the virtual
unwind of stack activations is complete.

That is allows gdb and libunwind successfully stop when unwinding stack
from global constructors and destructors.

Reviewed by:		kib
Differential Revision:	https://reviews.freebsd.org/D40794
2023-07-01 10:51:35 +03:00

176 lines
5.3 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:
.cfi_startproc
.cfi_undefined %rip
xorq %rbp,%rbp # Clear frame pointer for good form
subq $24,%rsp # A place to store exit procedure addr
.cfi_def_cfa_offset 32
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
.cfi_def_cfa_offset 24
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
.cfi_endproc
/*
* 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