mirror of
https://github.com/darlinghq/darling.git
synced 2024-11-24 12:49:44 +00:00
Csu-88
This commit is contained in:
parent
955cf9f4cb
commit
101c907f39
302
src/csu/dyld_glue.S
Normal file
302
src/csu/dyld_glue.S
Normal file
@ -0,0 +1,302 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2008 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
#if __ppc__ && __PIC__
|
||||
//
|
||||
// Force stub section next to __text section to minimize chance that
|
||||
// a bl to a stub will be out of range.
|
||||
//
|
||||
.text
|
||||
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The dyld_stub_binding_helper adds the mach_header parameter
|
||||
// and then jumps into dyld via a pointer in __dyld section
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
.text
|
||||
.private_extern dyld_stub_binding_helper
|
||||
.align 2
|
||||
dyld_stub_binding_helper:
|
||||
|
||||
#if __ppc__
|
||||
// for ppc the mach_header parameter is place in r12
|
||||
// and the lazy_pointer is already in r11
|
||||
#if __PIC__
|
||||
mflr r0
|
||||
bcl 20,31,L1
|
||||
L1: mflr r12
|
||||
mtlr r0
|
||||
mr r0,r12
|
||||
addis r12,r12,ha16(Ldyld_content_lazy_binder-L1)
|
||||
lwz r12,lo16(Ldyld_content_lazy_binder-L1)(r12)
|
||||
mtctr r12
|
||||
mr r12,r0
|
||||
addis r12,r12,ha16(dyld__mach_header-L1)
|
||||
lwz r12,lo16(dyld__mach_header-L1)(r12)
|
||||
bctr
|
||||
#else
|
||||
lis r12,ha16(Ldyld_content_lazy_binder)
|
||||
lwz r12,lo16(Ldyld_content_lazy_binder)(r12)
|
||||
mtctr r12
|
||||
lis r12,ha16(___dso_handle)
|
||||
la r12,lo16(___dso_handle)(r12)
|
||||
bctr
|
||||
#endif
|
||||
|
||||
#elif __ppc64__
|
||||
// for ppc the mach_header parameter is place in r12
|
||||
// and the lazy_pointer is already in r11
|
||||
// always use PIC code so we can have 4GB zero page
|
||||
mflr r0
|
||||
bcl 20,31,L1
|
||||
L1: mflr r12
|
||||
mtlr r0
|
||||
mr r0,r12
|
||||
addis r12,r12,ha16(Ldyld_content_lazy_binder-L1)
|
||||
ld r12,lo16(Ldyld_content_lazy_binder-L1)(r12)
|
||||
mtctr r12
|
||||
mr r12,r0
|
||||
addis r12,r12,ha16(dyld__mach_header-L1)
|
||||
ld r12,lo16(dyld__mach_header-L1)(r12)
|
||||
bctr
|
||||
|
||||
#elif __i386__
|
||||
// for i386 the mach_header parameter is pushed on the stack
|
||||
// and the lazy_pointer is already on the stack
|
||||
#if __PIC__
|
||||
subl $8,%esp
|
||||
pushl %eax
|
||||
pushl %ecx
|
||||
call L1
|
||||
L1: popl %eax
|
||||
movl dyld__mach_header-L1(%eax),%ecx
|
||||
movl %ecx,12(%esp)
|
||||
movl Ldyld_content_lazy_binder-L1(%eax),%ecx
|
||||
movl %ecx,8(%esp)
|
||||
popl %ecx
|
||||
popl %eax
|
||||
ret // jumps into dyld with lp and mh on the stack
|
||||
#else
|
||||
pushl $___dso_handle
|
||||
jmpl *Ldyld_content_lazy_binder
|
||||
#endif
|
||||
|
||||
#elif __x86_64__
|
||||
// for x86_64 the mach_header parameter is pushed on the stack
|
||||
// and the lazy_pointer was in r11 and is pushed on the stack
|
||||
pushq %r11
|
||||
leaq ___dso_handle(%rip), %r11
|
||||
pushq %r11
|
||||
jmp *Ldyld_content_lazy_binder(%rip)
|
||||
|
||||
#elif __arm__
|
||||
str ip, [sp, #-4]! // push address of lazy pointer
|
||||
ldr ip, Ldyld__mach_header_pointer
|
||||
#if __PIC__
|
||||
Ldyld__mach_header_pointer_base:
|
||||
ldr ip, [pc, ip]
|
||||
#endif
|
||||
str ip, [sp, #-4]! // push address of mach header
|
||||
ldr ip, Ldyld_lazy_symbol_binding_entry_point
|
||||
#if __PIC__
|
||||
Ldyld_lazy_symbol_binding_entry_point_base:
|
||||
ldr pc, [pc, ip] // jump to dyld_lazy_symbol_binding_entry_point
|
||||
#else
|
||||
ldr pc, [ip]
|
||||
#endif
|
||||
|
||||
Ldyld__mach_header_pointer:
|
||||
#if __PIC__
|
||||
.long dyld__mach_header - (Ldyld__mach_header_pointer_base + 8)
|
||||
#else
|
||||
.long ___dso_handle
|
||||
#endif
|
||||
Ldyld_lazy_symbol_binding_entry_point:
|
||||
#if __PIC__
|
||||
.long Ldyld_content_lazy_binder - (Ldyld_lazy_symbol_binding_entry_point_base + 8)
|
||||
#else
|
||||
.long Ldyld_content_lazy_binder
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// cfm_stub_binding_helper
|
||||
//
|
||||
// only needed by ppc dylibs which support CFM clients
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
#if __ppc__ && CFM_GLUE
|
||||
.text
|
||||
.align 2
|
||||
.private_extern cfm_stub_binding_helper
|
||||
cfm_stub_binding_helper:
|
||||
mr r11, r12 ; The TVector address is the binding pointer address.
|
||||
b dyld_stub_binding_helper ; Let the normal code handle the rest.
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// __dyld_func_lookup(const char*, void**)
|
||||
//
|
||||
// jumps into dyld via a pointer in __dyld section
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
.text
|
||||
.private_extern __dyld_func_lookup
|
||||
.align 2
|
||||
__dyld_func_lookup:
|
||||
|
||||
#if __ppc__
|
||||
#if __PIC__
|
||||
mflr r0
|
||||
bcl 20,31,L2
|
||||
L2: mflr r11
|
||||
mtlr r0
|
||||
addis r11,r11,ha16(Ldyld_content_func_lookup-L2)
|
||||
lwz r11,lo16(Ldyld_content_func_lookup-L2)(r11)
|
||||
mtctr r11
|
||||
bctr
|
||||
#else
|
||||
lis r11,ha16(Ldyld_content_func_lookup)
|
||||
lwz r11,lo16(Ldyld_content_func_lookup)(r11)
|
||||
mtctr r11
|
||||
bctr
|
||||
#endif
|
||||
|
||||
#elif __ppc64__
|
||||
mflr r0
|
||||
bcl 20,31,L2
|
||||
L2: mflr r11
|
||||
mtlr r0
|
||||
addis r11,r11,ha16(Ldyld_content_func_lookup-L2)
|
||||
ld r11,lo16(Ldyld_content_func_lookup-L2)(r11)
|
||||
mtctr r11
|
||||
bctr
|
||||
|
||||
#elif __i386__
|
||||
#if __PIC__
|
||||
call L2
|
||||
L2: popl %eax
|
||||
movl Ldyld_content_func_lookup-L2(%eax),%eax
|
||||
jmpl *%eax
|
||||
#else
|
||||
jmpl *Ldyld_content_func_lookup
|
||||
#endif
|
||||
|
||||
#elif __x86_64__
|
||||
jmp *Ldyld_content_func_lookup(%rip)
|
||||
|
||||
#elif __arm__
|
||||
ldr ip, L__dyld_func_lookup_pointer
|
||||
#if __PIC__
|
||||
L__dyld_func_lookup_pointer_base:
|
||||
ldr pc, [pc, ip]
|
||||
#else
|
||||
ldr pc, [ip]
|
||||
#endif
|
||||
L__dyld_func_lookup_pointer:
|
||||
#if __PIC__
|
||||
.long Ldyld_content_func_lookup - (L__dyld_func_lookup_pointer_base + 8)
|
||||
#else
|
||||
.long Ldyld_content_func_lookup
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if __LP64__
|
||||
#define align_pointer align 3
|
||||
#define pointer quad
|
||||
#else
|
||||
#define align_pointer align 2
|
||||
#define pointer long
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if __ppc64__ || ((__i386__ || __ppc__ || __arm__) && __PIC__)
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// dyld__mach_header
|
||||
// contains a pointer to the mach_header for this linkage unit
|
||||
// only needed for some code models
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
.data
|
||||
.align_pointer
|
||||
dyld__mach_header:
|
||||
.pointer ___dso_handle
|
||||
#endif // __x86_64__
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// __dyld section content
|
||||
//
|
||||
// 0: pointer to lazy symbol binder in dyld
|
||||
// 1: pointer to dyld_func_lookup implementation in dyld
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
#if __ppc__
|
||||
Ldyld_base_addr = 0x8fe00000
|
||||
#elif __ppc64__
|
||||
Ldyld_base_addr = 0x00007fff5fc00000
|
||||
#elif __i386__
|
||||
Ldyld_base_addr = 0x8fe00000
|
||||
#elif __x86_64__
|
||||
Ldyld_base_addr = 0x00007fff5fc00000
|
||||
#elif __arm__
|
||||
Ldyld_base_addr = 0x2fe00000
|
||||
#elif __arm64__
|
||||
#else
|
||||
#error unknown architecture
|
||||
#endif
|
||||
|
||||
#if !__arm64__
|
||||
.dyld
|
||||
.align_pointer
|
||||
Ldyld_content_lazy_binder:
|
||||
.pointer Ldyld_base_addr + 0x1000
|
||||
Ldyld_content_func_lookup:
|
||||
.pointer Ldyld_base_addr + 0x1008
|
||||
#if CRT && !OLD_LIBSYSTEM_SUPPORT
|
||||
.pointer ___dso_handle
|
||||
.pointer _NXArgc
|
||||
.pointer _NXArgv
|
||||
.pointer _environ
|
||||
.pointer ___progname
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// This code has be written to allow dead code stripping
|
||||
.subsections_via_symbols
|
||||
|
33
src/csu/icplusplus.c
Normal file
33
src/csu/icplusplus.c
Normal file
@ -0,0 +1,33 @@
|
||||
#include <stdlib.h>
|
||||
#include <mach-o/ldsyms.h>
|
||||
|
||||
__private_extern__
|
||||
int _dyld_func_lookup(
|
||||
const char *dyld_func_name,
|
||||
unsigned long *address);
|
||||
|
||||
|
||||
#if defined(__ppc__)
|
||||
/*
|
||||
* __initialize_Cplusplus() is a symbols specific to each shared library that
|
||||
* can be called in the shared library's initialization routine to force the
|
||||
* C++ runtime to be initialized so it can be used. Shared library
|
||||
* initialization routines are called before C++ static initializers are called
|
||||
* so if a shared library's initialization routine depends on them it must make
|
||||
* a call to __initialize_Cplusplus() first.
|
||||
*
|
||||
* This function is deprecated in Mac OS X 10.4 because C++ static initializers
|
||||
* are now called in the correct order. Therefore, no ppc64 program needs this.
|
||||
*/
|
||||
__private_extern__
|
||||
void
|
||||
__initialize_Cplusplus(void)
|
||||
{
|
||||
void (*p)(const struct mach_header *);
|
||||
|
||||
_dyld_func_lookup("__dyld_call_module_initializers_for_dylib",
|
||||
(unsigned long *)&p);
|
||||
if(p != NULL)
|
||||
p(&_mh_dylib_header);
|
||||
}
|
||||
#endif /* !defined(__ppc64__) */
|
261
src/csu/lazy_dylib_helper.S
Normal file
261
src/csu/lazy_dylib_helper.S
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (c) 1999-2008 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#if __i386__
|
||||
/*
|
||||
* This is the implementation of dyld_lazy_dylib_stub_binding_helper for i386
|
||||
* on versions before Macs OS X 10.6. On entry the address of the lazy pointer
|
||||
* has been pushed on the stack.
|
||||
*
|
||||
* After the symbol has been resolved and the lazy pointer filled in, this jumps
|
||||
* to the target address.
|
||||
*/
|
||||
#define LP_PARAM_OUT 0
|
||||
#define XMMM0_SAVE 16 /* 16-byte align */
|
||||
#define XMMM1_SAVE 32
|
||||
#define XMMM2_SAVE 48
|
||||
#define XMMM3_SAVE 64
|
||||
#define EAX_SAVE 84
|
||||
#define ECX_SAVE 88
|
||||
#define EDX_SAVE 92
|
||||
#define LP_LOCAL 96
|
||||
#define STACK_SIZE 104 /* must be 8 mod 16 so that stack winds up 16-byte aliged */
|
||||
#define LP_OLD_BP_SAVE 104
|
||||
|
||||
.text
|
||||
.align 4,0x90
|
||||
.globl dyld_lazy_dylib_stub_binding_helper
|
||||
.private_extern dyld_lazy_dylib_stub_binding_helper
|
||||
dyld_lazy_dylib_stub_binding_helper:
|
||||
subl $STACK_SIZE,%esp # makes stack 16-byte aligned
|
||||
movl %eax,EAX_SAVE(%esp)
|
||||
movl LP_OLD_BP_SAVE(%esp),%eax # get lazy-pointer meta-parameter
|
||||
movl %eax,LP_LOCAL(%esp)
|
||||
movl %ebp,LP_OLD_BP_SAVE(%esp) # store epb back chain
|
||||
movl %esp,%ebp # set epb to be this frame
|
||||
add $LP_OLD_BP_SAVE,%ebp
|
||||
movl %ecx,ECX_SAVE(%esp)
|
||||
movl %edx,EDX_SAVE(%esp)
|
||||
movdqu %xmm0,XMMM0_SAVE(%esp)
|
||||
movdqu %xmm1,XMMM1_SAVE(%esp)
|
||||
movdqu %xmm2,XMMM2_SAVE(%esp)
|
||||
movdqu %xmm3,XMMM3_SAVE(%esp)
|
||||
movl LP_LOCAL(%esp),%eax
|
||||
movl %eax,LP_PARAM_OUT(%esp) # call lazy_load_dylib(lazy_ptr)
|
||||
call _lazy_load_dylib
|
||||
movdqu XMMM0_SAVE(%esp),%xmm0 # restore registers
|
||||
movdqu XMMM1_SAVE(%esp),%xmm1
|
||||
movdqu XMMM2_SAVE(%esp),%xmm2
|
||||
movdqu XMMM3_SAVE(%esp),%xmm3
|
||||
movl ECX_SAVE(%esp),%ecx
|
||||
movl EDX_SAVE(%esp),%edx
|
||||
movl %eax,%ebp # move target address to epb
|
||||
movl EAX_SAVE(%esp),%eax # restore eax
|
||||
addl $STACK_SIZE,%esp # cut back stack
|
||||
xchg %ebp, (%esp) # restore ebp and set target to top of stack
|
||||
ret # jump to target
|
||||
|
||||
#endif /* __i386__ */
|
||||
|
||||
|
||||
#if __x86_64__
|
||||
/*
|
||||
* This is the implementation of dyld_lazy_dylib_stub_binding_helper for x86_64
|
||||
* on versions before Macs OS X 10.6. On entry r11 contains address of the
|
||||
* lazy pointer.
|
||||
*
|
||||
* All parameters registers must be preserved.
|
||||
*
|
||||
* After the symbol has been resolved and the pointer filled in this is to pop
|
||||
* these arguments off the stack and jump to the address of the defined symbol.
|
||||
*/
|
||||
#define RDI_SAVE 0
|
||||
#define RSI_SAVE 8
|
||||
#define RDX_SAVE 16
|
||||
#define RCX_SAVE 24
|
||||
#define R8_SAVE 32
|
||||
#define R9_SAVE 40
|
||||
#define RAX_SAVE 48
|
||||
#define XMMM0_SAVE 64 /* 16-byte align */
|
||||
#define XMMM1_SAVE 80
|
||||
#define XMMM2_SAVE 96
|
||||
#define XMMM3_SAVE 112
|
||||
#define XMMM4_SAVE 128
|
||||
#define XMMM5_SAVE 144
|
||||
#define XMMM6_SAVE 160
|
||||
#define XMMM7_SAVE 176
|
||||
#define STACK_SIZE 192 /* (XMMM7_SAVE+16) must be 16 byte aligned too */
|
||||
|
||||
.text
|
||||
.align 2,0x90
|
||||
.globl dyld_lazy_dylib_stub_binding_helper
|
||||
.private_extern dyld_lazy_dylib_stub_binding_helper
|
||||
dyld_lazy_dylib_stub_binding_helper:
|
||||
pushq %rbp
|
||||
movq %rsp,%rbp
|
||||
subq $STACK_SIZE,%rsp
|
||||
movq %rdi,RDI_SAVE(%rsp) # save registers that might be used as parameters
|
||||
movq %rsi,RSI_SAVE(%rsp)
|
||||
movq %rdx,RDX_SAVE(%rsp)
|
||||
movq %rcx,RCX_SAVE(%rsp)
|
||||
movq %r8,R8_SAVE(%rsp)
|
||||
movq %r9,R9_SAVE(%rsp)
|
||||
movq %rax,RAX_SAVE(%rsp)
|
||||
movdqa %xmm0,XMMM0_SAVE(%rsp)
|
||||
movdqa %xmm1,XMMM1_SAVE(%rsp)
|
||||
movdqa %xmm2,XMMM2_SAVE(%rsp)
|
||||
movdqa %xmm3,XMMM3_SAVE(%rsp)
|
||||
movdqa %xmm4,XMMM4_SAVE(%rsp)
|
||||
movdqa %xmm5,XMMM5_SAVE(%rsp)
|
||||
movdqa %xmm6,XMMM6_SAVE(%rsp)
|
||||
movdqa %xmm7,XMMM7_SAVE(%rsp)
|
||||
movq %r11,%rdi # call lazy_load_dylib(lazy_ptr)
|
||||
call _lazy_load_dylib
|
||||
movq %rax,%r11 # save target
|
||||
movdqa XMMM0_SAVE(%rsp),%xmm0 # restore registers
|
||||
movdqa XMMM1_SAVE(%rsp),%xmm1
|
||||
movdqa XMMM2_SAVE(%rsp),%xmm2
|
||||
movdqa XMMM3_SAVE(%rsp),%xmm3
|
||||
movdqa XMMM4_SAVE(%rsp),%xmm4
|
||||
movdqa XMMM5_SAVE(%rsp),%xmm5
|
||||
movdqa XMMM6_SAVE(%rsp),%xmm6
|
||||
movdqa XMMM7_SAVE(%rsp),%xmm7
|
||||
movq RDI_SAVE(%rsp),%rdi
|
||||
movq RSI_SAVE(%rsp),%rsi
|
||||
movq RDX_SAVE(%rsp),%rdx
|
||||
movq RCX_SAVE(%rsp),%rcx
|
||||
movq R8_SAVE(%rsp),%r8
|
||||
movq R9_SAVE(%rsp),%r9
|
||||
movq RAX_SAVE(%rsp),%rax
|
||||
addq $STACK_SIZE,%rsp
|
||||
popq %rbp
|
||||
jmp *%r11 # jmp to target
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if __ppc__ || __ppc64__
|
||||
#include <architecture/ppc/mode_independent_asm.h>
|
||||
/*
|
||||
* This is the implementation of dyld_lazy_dylib_stub_binding_helper for ppc
|
||||
* on versions before Macs OS X 10.6. On entry r11 contains address of the
|
||||
* lazy pointer to be filled
|
||||
*
|
||||
* r11 address of lazy pointer
|
||||
*/
|
||||
#define LRSAVE MODE_CHOICE(8,16)
|
||||
#define STACK_SIZE MODE_CHOICE(144,288)
|
||||
#define R3SAVE MODE_CHOICE(56,112)
|
||||
#define R4SAVE MODE_CHOICE(60,120)
|
||||
#define R5SAVE MODE_CHOICE(64,128)
|
||||
#define R6SAVE MODE_CHOICE(68,136)
|
||||
#define R7SAVE MODE_CHOICE(72,144)
|
||||
#define R8SAVE MODE_CHOICE(76,152)
|
||||
#define R9SAVE MODE_CHOICE(80,160)
|
||||
#define R10SAVE MODE_CHOICE(84,168)
|
||||
|
||||
|
||||
.text
|
||||
.align 2
|
||||
.globl dyld_lazy_dylib_stub_binding_helper
|
||||
.private_extern dyld_lazy_dylib_stub_binding_helper
|
||||
dyld_lazy_dylib_stub_binding_helper:
|
||||
mflr r0 ; get link register value
|
||||
stg r0,LRSAVE(r1) ; save link register value in the linkage area
|
||||
stgu r1,-STACK_SIZE(r1) ; save stack pointer and update it
|
||||
|
||||
stg r3,R3SAVE(r1) ; save all registers that could contain
|
||||
stg r4,R4SAVE(r1) ; parameters to the routine that is being
|
||||
stg r5,R5SAVE(r1) ; bound.
|
||||
stg r6,R6SAVE(r1)
|
||||
stg r7,R7SAVE(r1)
|
||||
stg r8,R8SAVE(r1)
|
||||
stg r9,R9SAVE(r1)
|
||||
stg r10,R10SAVE(r1)
|
||||
|
||||
mr r3,r11 ; move address of lazy pointer to 1st parameter
|
||||
; call lazy_load_dylib(lazy_ptr)
|
||||
bl _lazy_load_dylib
|
||||
mr r12,r3 ; move the symbol`s address into r12
|
||||
mtctr r12 ; move the symbol`s address into count register
|
||||
|
||||
lg r0,STACK_SIZE+LRSAVE(r1) ; get old link register value
|
||||
|
||||
lg r3,R3SAVE(r1) ; restore all registers that could contain
|
||||
lg r4,R4SAVE(r1) ; parameters to the routine that was bound.
|
||||
lg r5,R5SAVE(r1)
|
||||
lg r6,R6SAVE(r1)
|
||||
lg r7,R7SAVE(r1)
|
||||
lg r8,R8SAVE(r1)
|
||||
lg r9,R9SAVE(r1)
|
||||
lg r10,R10SAVE(r1)
|
||||
|
||||
addi r1,r1,STACK_SIZE; restore old stack pointer
|
||||
mtlr r0 ; restore link register
|
||||
|
||||
bctr ; jump to the symbol`s address that was bound
|
||||
|
||||
#endif /* __ppc__ */
|
||||
|
||||
#if __arm__
|
||||
/*
|
||||
* This is the implementation of dyld_lazy_dylib_stub_binding_helper for ARM
|
||||
* The caller has pushed the address of the a lazy pointer to be filled in with
|
||||
* the value for the defined symbol
|
||||
*
|
||||
* ip address of lazy pointer
|
||||
*
|
||||
* After the symbol has been resolved and the pointer filled in this is to pop
|
||||
* these arguments off the stack and jump to the address of the defined symbol.
|
||||
*/
|
||||
.text
|
||||
.align 2
|
||||
.globl dyld_lazy_dylib_stub_binding_helper
|
||||
.private_extern dyld_lazy_dylib_stub_binding_helper
|
||||
dyld_lazy_dylib_stub_binding_helper:
|
||||
stmfd sp!, {r0,r1,r2,r3,r7,lr} // save registers
|
||||
add r7, sp, #16 // point FP to previous FP
|
||||
|
||||
mov r0, ip // move address of lazy pointer to 1st parameter
|
||||
// call lazy_load_dylib(lazy_ptr)
|
||||
bl _lazy_load_dylib
|
||||
mov ip, r0 // move the symbol`s address into ip
|
||||
|
||||
ldmfd sp!, {r0,r1,r2,r3,r7,lr} // restore registers
|
||||
|
||||
bx ip // jump to the symbol`s address that was bound
|
||||
|
||||
#endif /* __arm__ */
|
||||
|
||||
|
||||
|
||||
|
||||
// This code has be written to allow dead code stripping
|
||||
.subsections_via_symbols
|
||||
|
||||
|
||||
|
||||
|
||||
|
231
src/csu/lazy_dylib_loader.c
Normal file
231
src/csu/lazy_dylib_loader.c
Normal file
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2012 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*/
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/nlist.h>
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#ifndef LC_LAZY_LOAD_DYLIB
|
||||
#define LC_LAZY_LOAD_DYLIB 0x20
|
||||
#endif
|
||||
#ifndef S_LAZY_DYLIB_SYMBOL_POINTERS
|
||||
#define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10
|
||||
#endif
|
||||
#ifndef LC_LOAD_UPWARD_DYLIB
|
||||
#define LC_LOAD_UPWARD_DYLIB (0x23 | LC_REQ_DYLD) /* load upward dylib */
|
||||
#endif
|
||||
|
||||
#if __LP64__
|
||||
#define LC_SEGMENT_COMMAND LC_SEGMENT_64
|
||||
#define LC_ROUTINES_COMMAND LC_ROUTINES_64
|
||||
typedef struct mach_header_64 macho_header;
|
||||
typedef struct section_64 macho_section;
|
||||
typedef struct nlist_64 macho_nlist;
|
||||
typedef struct segment_command_64 macho_segment_command;
|
||||
#else
|
||||
#define LC_SEGMENT_COMMAND LC_SEGMENT
|
||||
#define LC_ROUTINES_COMMAND LC_ROUTINES
|
||||
typedef struct mach_header macho_header;
|
||||
typedef struct section macho_section;
|
||||
typedef struct nlist macho_nlist;
|
||||
typedef struct segment_command macho_segment_command;
|
||||
#endif
|
||||
|
||||
extern const macho_header __dso_handle;
|
||||
|
||||
|
||||
// This function may be overriden by application code
|
||||
// to do custom error handling when a lazy symbol cannot be
|
||||
// resolved.
|
||||
int dyld_lazy_dylib_proxy() __attribute__((weak,visibility("hidden")));
|
||||
int dyld_lazy_dylib_proxy()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// This function may be overriden by application code
|
||||
// to dynamically change the path to a loaded lazy dylib.
|
||||
const char* dyld_lazy_dylib_path_fix(const char*) __attribute__((weak,visibility("hidden")));
|
||||
const char* dyld_lazy_dylib_path_fix(const char* path)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
static void* getHandleForLazyOrdinal(const macho_header* mh, void* handles[], uint8_t ordinal)
|
||||
{
|
||||
const uint32_t cmd_count = mh->ncmds;
|
||||
const struct load_command* const cmds = (struct load_command*)((char*)mh + sizeof(macho_header));
|
||||
const struct load_command* cmd = cmds;
|
||||
uint8_t loadDylibCount = 0;
|
||||
uint8_t loadLazyDylibCount = 0;
|
||||
uint32_t i;
|
||||
// walk load commands to find LC_LAZY_LOAD_DYLIB that matches ordinal
|
||||
for (i = 0; i < cmd_count; ++i) {
|
||||
switch ( cmd->cmd ) {
|
||||
case LC_LOAD_DYLIB:
|
||||
case LC_LOAD_WEAK_DYLIB:
|
||||
case LC_LOAD_UPWARD_DYLIB:
|
||||
++loadDylibCount;
|
||||
break;
|
||||
case LC_LAZY_LOAD_DYLIB:
|
||||
++loadDylibCount;
|
||||
if ( loadDylibCount == ordinal ) {
|
||||
if ( handles[loadLazyDylibCount] == NULL ) {
|
||||
const struct dylib_command* dylib = (struct dylib_command*)cmd;
|
||||
const char* path = (char*)cmd + dylib->dylib.name.offset;
|
||||
const char* fixedPath = dyld_lazy_dylib_path_fix(path);
|
||||
handles[loadLazyDylibCount] = dlopen(fixedPath, RTLD_LAZY);
|
||||
}
|
||||
return handles[loadLazyDylibCount];
|
||||
}
|
||||
++loadLazyDylibCount;
|
||||
break;
|
||||
}
|
||||
cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// called by dyld_lazy_dylib_stub_binding_helper
|
||||
// this function must figure out which function
|
||||
// lazyPointer is supposed to point to
|
||||
// and update it it.
|
||||
void* lazy_load_dylib(uintptr_t* lazyPointer) __attribute__((visibility("hidden")));
|
||||
void* lazy_load_dylib(uintptr_t* lazyPointer)
|
||||
{
|
||||
static const macho_header* mh = NULL;
|
||||
static const macho_nlist* symbolTable = NULL;
|
||||
static const char* stringTable = NULL;
|
||||
static const uint8_t* linkEditBase = NULL;
|
||||
static const uint32_t* indirectSymbolTable = NULL;
|
||||
static intptr_t slide = 0;
|
||||
static void* minHandles[8];
|
||||
static void** handles;
|
||||
|
||||
// do this work only on first call
|
||||
uint32_t i;
|
||||
if ( mh == NULL ) {
|
||||
const macho_header* tmh = &__dso_handle;
|
||||
// symbol table, indirect symbol table
|
||||
const uint32_t cmd_count = tmh->ncmds;
|
||||
const struct load_command* const cmds = (struct load_command*)((char*)tmh + sizeof(macho_header));
|
||||
const struct load_command* cmd = cmds;
|
||||
// first pass at load commands gets linkEditBase
|
||||
for (i = 0; i < cmd_count; ++i) {
|
||||
if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
|
||||
const macho_segment_command* seg = (macho_segment_command*)cmd;
|
||||
if ( strcmp(seg->segname,"__TEXT") == 0 )
|
||||
slide = (uintptr_t)tmh - seg->vmaddr;
|
||||
else if ( strcmp(seg->segname,"__LINKEDIT") == 0 )
|
||||
linkEditBase = (uint8_t*)(seg->vmaddr + slide - seg->fileoff);
|
||||
}
|
||||
cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
|
||||
}
|
||||
// next pass at load commands gets symbolTable, stringTable
|
||||
uint32_t lazyDylibCount = 0;
|
||||
cmd = cmds;
|
||||
for (i = 0; i < cmd_count; ++i) {
|
||||
switch ( cmd->cmd ) {
|
||||
case LC_SYMTAB:
|
||||
{
|
||||
const struct symtab_command* symtab = (struct symtab_command*)cmd;
|
||||
stringTable = (const char*)&linkEditBase[symtab->stroff];
|
||||
symbolTable = (macho_nlist*)(&linkEditBase[symtab->symoff]);
|
||||
}
|
||||
break;
|
||||
case LC_DYSYMTAB:
|
||||
{
|
||||
const struct dysymtab_command* dsymtab = (struct dysymtab_command*)cmd;
|
||||
indirectSymbolTable = (uint32_t*)(&linkEditBase[dsymtab->indirectsymoff]);
|
||||
}
|
||||
break;
|
||||
case LC_LAZY_LOAD_DYLIB:
|
||||
++lazyDylibCount;
|
||||
break;
|
||||
}
|
||||
cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
|
||||
}
|
||||
// use static buffer when possible
|
||||
if ( lazyDylibCount < 8 )
|
||||
handles = minHandles;
|
||||
else
|
||||
handles = calloc(lazyDylibCount, sizeof(void*));
|
||||
|
||||
// save to static global to make this thread safe
|
||||
mh = tmh;
|
||||
}
|
||||
|
||||
// find lazy dylib pointer section
|
||||
void* result = &dyld_lazy_dylib_proxy;
|
||||
const uint32_t cmd_count = mh->ncmds;
|
||||
const struct load_command* const cmds = (struct load_command*)((char*)mh + sizeof(macho_header));
|
||||
const struct load_command* cmd = cmds;
|
||||
// walk sections to find one with this lazy pointer
|
||||
for (i = 0; i < cmd_count; ++i) {
|
||||
if ( cmd->cmd == LC_SEGMENT_COMMAND ) {
|
||||
const macho_segment_command* seg = (macho_segment_command*)cmd;
|
||||
const macho_section* const sectionsStart = (macho_section*)((char*)seg + sizeof(macho_segment_command));
|
||||
const macho_section* const sectionsEnd = §ionsStart[seg->nsects];
|
||||
const macho_section* sect;
|
||||
for (sect=sectionsStart; sect < sectionsEnd; ++sect) {
|
||||
const uint8_t type = sect->flags & SECTION_TYPE;
|
||||
if ( type == S_LAZY_DYLIB_SYMBOL_POINTERS ) { // S_LAZY_DYLIB_SYMBOL_POINTERS
|
||||
const uint32_t pointerCount = sect->size / sizeof(uintptr_t);
|
||||
uintptr_t* const symbolPointers = (uintptr_t*)(sect->addr + slide);
|
||||
if ( (lazyPointer >= symbolPointers) && (lazyPointer < &symbolPointers[pointerCount]) ) {
|
||||
const uint32_t indirectTableOffset = sect->reserved1;
|
||||
const uint32_t lazyIndex = lazyPointer - symbolPointers;
|
||||
uint32_t symbolIndex = indirectSymbolTable[indirectTableOffset + lazyIndex];
|
||||
if ( symbolIndex != INDIRECT_SYMBOL_ABS && symbolIndex != INDIRECT_SYMBOL_LOCAL ) {
|
||||
// found symbol for this lazy pointer, now lookup address
|
||||
const char* symbolName = &stringTable[symbolTable[symbolIndex].n_un.n_strx];
|
||||
uint8_t ordinal = GET_LIBRARY_ORDINAL(symbolTable[symbolIndex].n_desc);
|
||||
void* handle = getHandleForLazyOrdinal(mh, handles, ordinal);
|
||||
if ( handle != NULL ) {
|
||||
void* addr = dlsym(handle, &symbolName[1]);
|
||||
if ( addr != NULL )
|
||||
result = addr;
|
||||
*lazyPointer = (uintptr_t)result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
|
||||
}
|
||||
*lazyPointer = (uintptr_t)result;
|
||||
return result;
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
// Modified by Lubos Dolezel for Darling
|
||||
/*
|
||||
* Copyright (c) 1999-2009 Apple Inc. All rights reserved.
|
||||
*
|
||||
@ -193,7 +192,7 @@ start:
|
||||
add r1, sp, #4 // get argv into r1
|
||||
add r4, r0, #1 // calculate argc + 1 into r4
|
||||
add r2, r1, r4, lsl #2 // get address of env[0] into r2
|
||||
bic sp, sp, #7 // force eight-byte alignment
|
||||
bic sp, sp, #15 // force sixteen-byte alignment
|
||||
#if OLD_LIBSYSTEM_SUPPORT
|
||||
bl __start
|
||||
.long 0xe1200070 // should never return
|
||||
@ -261,4 +260,4 @@ L1: ldr x4, [x3], #8
|
||||
|
||||
|
||||
// This code has be written to allow dead code stripping
|
||||
// .subsections_via_symbols
|
||||
.subsections_via_symbols
|
||||
|
Loading…
Reference in New Issue
Block a user