This commit is contained in:
Ariel Abreu 2020-06-16 09:20:52 -04:00
parent 955cf9f4cb
commit 101c907f39
No known key found for this signature in database
GPG Key ID: F4D43CC7053EA2B3
5 changed files with 829 additions and 3 deletions

302
src/csu/dyld_glue.S Normal file
View 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
View 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
View 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
View 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 = &sectionsStart[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;
}

View File

@ -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