2 * Copyright (c) 2008-2012 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
27 #include <mach-o/loader.h>
28 #include <mach-o/nlist.h>
34 #ifndef LC_LAZY_LOAD_DYLIB
35 #define LC_LAZY_LOAD_DYLIB 0x20
37 #ifndef S_LAZY_DYLIB_SYMBOL_POINTERS
38 #define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10
40 #ifndef LC_LOAD_UPWARD_DYLIB
41 #define LC_LOAD_UPWARD_DYLIB (0x23 | LC_REQ_DYLD) /* load upward dylib */
45 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
46 #define LC_ROUTINES_COMMAND LC_ROUTINES_64
47 typedef struct mach_header_64 macho_header
;
48 typedef struct section_64 macho_section
;
49 typedef struct nlist_64 macho_nlist
;
50 typedef struct segment_command_64 macho_segment_command
;
52 #define LC_SEGMENT_COMMAND LC_SEGMENT
53 #define LC_ROUTINES_COMMAND LC_ROUTINES
54 typedef struct mach_header macho_header
;
55 typedef struct section macho_section
;
56 typedef struct nlist macho_nlist
;
57 typedef struct segment_command macho_segment_command
;
60 extern const macho_header __dso_handle
;
63 // This function may be overriden by application code
64 // to do custom error handling when a lazy symbol cannot be
66 int dyld_lazy_dylib_proxy() __attribute__((weak
,visibility("hidden")));
67 int dyld_lazy_dylib_proxy()
73 // This function may be overriden by application code
74 // to dynamically change the path to a loaded lazy dylib.
75 const char* dyld_lazy_dylib_path_fix(const char*) __attribute__((weak
,visibility("hidden")));
76 const char* dyld_lazy_dylib_path_fix(const char* path
)
82 static void* getHandleForLazyOrdinal(const macho_header
* mh
, void* handles
[], uint8_t ordinal
)
84 const uint32_t cmd_count
= mh
->ncmds
;
85 const struct load_command
* const cmds
= (struct load_command
*)((char*)mh
+ sizeof(macho_header
));
86 const struct load_command
* cmd
= cmds
;
87 uint8_t loadDylibCount
= 0;
88 uint8_t loadLazyDylibCount
= 0;
90 // walk load commands to find LC_LAZY_LOAD_DYLIB that matches ordinal
91 for (i
= 0; i
< cmd_count
; ++i
) {
94 case LC_LOAD_WEAK_DYLIB
:
95 case LC_LOAD_UPWARD_DYLIB
:
98 case LC_LAZY_LOAD_DYLIB
:
100 if ( loadDylibCount
== ordinal
) {
101 if ( handles
[loadLazyDylibCount
] == NULL
) {
102 const struct dylib_command
* dylib
= (struct dylib_command
*)cmd
;
103 const char* path
= (char*)cmd
+ dylib
->dylib
.name
.offset
;
104 const char* fixedPath
= dyld_lazy_dylib_path_fix(path
);
105 handles
[loadLazyDylibCount
] = dlopen(fixedPath
, RTLD_LAZY
);
107 return handles
[loadLazyDylibCount
];
109 ++loadLazyDylibCount
;
112 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
119 // called by dyld_lazy_dylib_stub_binding_helper
120 // this function must figure out which function
121 // lazyPointer is supposed to point to
123 void* lazy_load_dylib(uintptr_t* lazyPointer
) __attribute__((visibility("hidden")));
124 void* lazy_load_dylib(uintptr_t* lazyPointer
)
126 static const macho_header
* mh
= NULL
;
127 static const macho_nlist
* symbolTable
= NULL
;
128 static const char* stringTable
= NULL
;
129 static const uint8_t* linkEditBase
= NULL
;
130 static const uint32_t* indirectSymbolTable
= NULL
;
131 static intptr_t slide
= 0;
132 static void* minHandles
[8];
133 static void** handles
;
135 // do this work only on first call
138 const macho_header
* tmh
= &__dso_handle
;
139 // symbol table, indirect symbol table
140 const uint32_t cmd_count
= tmh
->ncmds
;
141 const struct load_command
* const cmds
= (struct load_command
*)((char*)tmh
+ sizeof(macho_header
));
142 const struct load_command
* cmd
= cmds
;
143 // first pass at load commands gets linkEditBase
144 for (i
= 0; i
< cmd_count
; ++i
) {
145 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
146 const macho_segment_command
* seg
= (macho_segment_command
*)cmd
;
147 if ( strcmp(seg
->segname
,"__TEXT") == 0 )
148 slide
= (uintptr_t)tmh
- seg
->vmaddr
;
149 else if ( strcmp(seg
->segname
,"__LINKEDIT") == 0 )
150 linkEditBase
= (uint8_t*)(seg
->vmaddr
+ slide
- seg
->fileoff
);
152 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
154 // next pass at load commands gets symbolTable, stringTable
155 uint32_t lazyDylibCount
= 0;
157 for (i
= 0; i
< cmd_count
; ++i
) {
158 switch ( cmd
->cmd
) {
161 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
162 stringTable
= (const char*)&linkEditBase
[symtab
->stroff
];
163 symbolTable
= (macho_nlist
*)(&linkEditBase
[symtab
->symoff
]);
168 const struct dysymtab_command
* dsymtab
= (struct dysymtab_command
*)cmd
;
169 indirectSymbolTable
= (uint32_t*)(&linkEditBase
[dsymtab
->indirectsymoff
]);
172 case LC_LAZY_LOAD_DYLIB
:
176 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
178 // use static buffer when possible
179 if ( lazyDylibCount
< 8 )
180 handles
= minHandles
;
182 handles
= calloc(lazyDylibCount
, sizeof(void*));
184 // save to static global to make this thread safe
188 // find lazy dylib pointer section
189 void* result
= &dyld_lazy_dylib_proxy
;
190 const uint32_t cmd_count
= mh
->ncmds
;
191 const struct load_command
* const cmds
= (struct load_command
*)((char*)mh
+ sizeof(macho_header
));
192 const struct load_command
* cmd
= cmds
;
193 // walk sections to find one with this lazy pointer
194 for (i
= 0; i
< cmd_count
; ++i
) {
195 if ( cmd
->cmd
== LC_SEGMENT_COMMAND
) {
196 const macho_segment_command
* seg
= (macho_segment_command
*)cmd
;
197 const macho_section
* const sectionsStart
= (macho_section
*)((char*)seg
+ sizeof(macho_segment_command
));
198 const macho_section
* const sectionsEnd
= §ionsStart
[seg
->nsects
];
199 const macho_section
* sect
;
200 for (sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
201 const uint8_t type
= sect
->flags
& SECTION_TYPE
;
202 if ( type
== S_LAZY_DYLIB_SYMBOL_POINTERS
) { // S_LAZY_DYLIB_SYMBOL_POINTERS
203 const uint32_t pointerCount
= sect
->size
/ sizeof(uintptr_t);
204 uintptr_t* const symbolPointers
= (uintptr_t*)(sect
->addr
+ slide
);
205 if ( (lazyPointer
>= symbolPointers
) && (lazyPointer
< &symbolPointers
[pointerCount
]) ) {
206 const uint32_t indirectTableOffset
= sect
->reserved1
;
207 const uint32_t lazyIndex
= lazyPointer
- symbolPointers
;
208 uint32_t symbolIndex
= indirectSymbolTable
[indirectTableOffset
+ lazyIndex
];
209 if ( symbolIndex
!= INDIRECT_SYMBOL_ABS
&& symbolIndex
!= INDIRECT_SYMBOL_LOCAL
) {
210 // found symbol for this lazy pointer, now lookup address
211 const char* symbolName
= &stringTable
[symbolTable
[symbolIndex
].n_un
.n_strx
];
212 uint8_t ordinal
= GET_LIBRARY_ORDINAL(symbolTable
[symbolIndex
].n_desc
);
213 void* handle
= getHandleForLazyOrdinal(mh
, handles
, ordinal
);
214 if ( handle
!= NULL
) {
215 void* addr
= dlsym(handle
, &symbolName
[1]);
218 *lazyPointer
= (uintptr_t)result
;
226 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
228 *lazyPointer
= (uintptr_t)result
;