modified: nfig1.py
[GalaxyCodeBases.git] / c_cpp / Mac / Csu-85 / lazy_dylib_loader.c
blob5683baf80dba4a607ff619cf19109d00273658a2
1 /*
2 * Copyright (c) 2008-2012 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
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@
25 #include <stddef.h>
26 #include <string.h>
27 #include <mach-o/loader.h>
28 #include <mach-o/nlist.h>
29 #include <stdlib.h>
30 #include <dlfcn.h>
31 #include <stdio.h>
34 #ifndef LC_LAZY_LOAD_DYLIB
35 #define LC_LAZY_LOAD_DYLIB 0x20
36 #endif
37 #ifndef S_LAZY_DYLIB_SYMBOL_POINTERS
38 #define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10
39 #endif
40 #ifndef LC_LOAD_UPWARD_DYLIB
41 #define LC_LOAD_UPWARD_DYLIB (0x23 | LC_REQ_DYLD) /* load upward dylib */
42 #endif
44 #if __LP64__
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;
51 #else
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;
58 #endif
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
65 // resolved.
66 int dyld_lazy_dylib_proxy() __attribute__((weak,visibility("hidden")));
67 int dyld_lazy_dylib_proxy()
69 return 0;
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)
78 return 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;
89 uint32_t i;
90 // walk load commands to find LC_LAZY_LOAD_DYLIB that matches ordinal
91 for (i = 0; i < cmd_count; ++i) {
92 switch ( cmd->cmd ) {
93 case LC_LOAD_DYLIB:
94 case LC_LOAD_WEAK_DYLIB:
95 case LC_LOAD_UPWARD_DYLIB:
96 ++loadDylibCount;
97 break;
98 case LC_LAZY_LOAD_DYLIB:
99 ++loadDylibCount;
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;
110 break;
112 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
114 return NULL;
119 // called by dyld_lazy_dylib_stub_binding_helper
120 // this function must figure out which function
121 // lazyPointer is supposed to point to
122 // and update it it.
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
136 uint32_t i;
137 if ( mh == NULL ) {
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;
156 cmd = cmds;
157 for (i = 0; i < cmd_count; ++i) {
158 switch ( cmd->cmd ) {
159 case LC_SYMTAB:
161 const struct symtab_command* symtab = (struct symtab_command*)cmd;
162 stringTable = (const char*)&linkEditBase[symtab->stroff];
163 symbolTable = (macho_nlist*)(&linkEditBase[symtab->symoff]);
165 break;
166 case LC_DYSYMTAB:
168 const struct dysymtab_command* dsymtab = (struct dysymtab_command*)cmd;
169 indirectSymbolTable = (uint32_t*)(&linkEditBase[dsymtab->indirectsymoff]);
171 break;
172 case LC_LAZY_LOAD_DYLIB:
173 ++lazyDylibCount;
174 break;
176 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
178 // use static buffer when possible
179 if ( lazyDylibCount < 8 )
180 handles = minHandles;
181 else
182 handles = calloc(lazyDylibCount, sizeof(void*));
184 // save to static global to make this thread safe
185 mh = tmh;
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 = &sectionsStart[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]);
216 if ( addr != NULL )
217 result = addr;
218 *lazyPointer = (uintptr_t)result;
219 return result;
226 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
228 *lazyPointer = (uintptr_t)result;
229 return result;