Chameleon

Chameleon Svn Source Tree

Root/branches/cparm/i386/boot2/modules.c

1/*
2 * Copyright 2010 Evan Lojewski. All rights reserved.
3 *
4 */
5
6#include "boot.h"
7#include "bootstruct.h"
8#include "multiboot.h"
9#include "modules.h"
10
11#ifndef DEBUG_MODULES
12#define DEBUG_MODULES 0
13#endif
14
15#if DEBUG_MODULES
16#define DBG(x...)printf(x)
17#else
18#define DBG(x...)
19#endif
20
21// NOTE: Global so that modules can link with this
22unsigned long long textAddress = 0;
23unsigned long long textSection = 0;
24
25moduleHook_t* moduleCallbacks = NULL;
26moduleList_t* loadedModules = NULL;
27symbolList_t* moduleSymbols = NULL;
28unsigned int (*lookup_symbol)(const char*) = NULL;
29
30#if DEBUG_MODULES
31VOID print_hook_list()
32{
33moduleHook_t* hooks = moduleCallbacks;
34printf("Hook list: \n");
35while(hooks)
36{
37printf("* %s\n", hooks->name);
38hooks = hooks->next;
39}
40printf("\n");
41}
42
43VOID print_symbol_list()
44{
45symbolList_t* symbol = moduleSymbols;
46printf("Symbol list: \n");
47while(symbol)
48{
49printf("* %s\n", symbol->symbol);
50symbol = symbol->next;
51}
52printf("\n");
53}
54#endif
55
56
57/*
58 * Initialize the module system by loading the Symbols.dylib module.
59 * Once loaded, locate the _lookup_symbol function so that internal
60 * symbols can be resolved.
61 */
62EFI_STATUS init_module_system()
63{
64msglog("* Attempting to load system module\n");
65
66// Intialize module system
67 EFI_STATUS status = load_module(SYMBOLS_MODULE);
68if((status == EFI_SUCCESS) || (status == EFI_ALREADY_STARTED)/*should never happen*/ )
69{
70lookup_symbol = (void*)lookup_all_symbols(SYMBOL_LOOKUP_SYMBOL);
71
72if((UInt32)lookup_symbol != 0xFFFFFFFF)
73{
74return status;
75}
76
77}
78
79return EFI_LOAD_ERROR;
80}
81
82
83/*
84 * Load all modules in the /Extra/modules/ directory
85 * Module depencdies will be loaded first
86 * MOdules will only be loaded once. When loaded a module must
87 * setup apropriete function calls and hooks as required.
88 * NOTE: To ensure a module loads after another you may
89 * link one module with the other. For dyld to allow this, you must
90 * reference at least one symbol within the module.
91 */
92
93VOID load_all_modules()
94{
95char* name;
96long flags;
97long time;
98struct dirstuff* moduleDir = opendir("/Extra/modules/");
99while(readdir(moduleDir, (const char**)&name, &flags, &time) >= 0)
100{
101if ((strcmp(SYMBOLS_MODULE,name)) == 0) continue; // if we found Symbols.dylib, just skip it
102
103int len = strlen(name);
104int ext_size = sizeof("dylib");
105
106if (len >= ext_size)
107{
108if(strcmp(&name[len - ext_size], ".dylib") == 0)
109{
110char* tmp = malloc(len /*+ 1*/);
111strlcpy(tmp, name, len + 1);
112msglog("* Attempting to load module: %s\n", tmp);
113if(load_module(tmp) != EFI_SUCCESS)
114{
115// failed to load or already loaded
116free(tmp);
117}
118}
119#if DEBUG_MODULES
120else
121{
122DBG("Ignoring %s\n", name);
123}
124#endif
125}
126#if DEBUG_MODULES
127else
128{
129DBG("Ignoring %s\n", name);
130}
131#endif
132
133}
134#if DEBUG_MODULES
135print_symbol_list();
136#endif
137}
138
139/*
140 * Load a module file in /Extra/modules
141 * TODO: verify version number of module
142 */
143EFI_STATUS load_module(char* module)
144{
145void (*module_start)(void) = NULL;
146
147
148// Check to see if the module has already been loaded
149if(is_module_loaded(module) == EFI_SUCCESS)
150{
151msglog("Module %s already registred\n", module);
152return EFI_ALREADY_STARTED;
153}
154
155char modString[128];
156int fh = -1;
157sprintf(modString, "/Extra/modules/%s", module);
158fh = open(modString);
159if(fh < 0)
160{
161#if DEBUG_MODULES
162DBG("Unable to locate module %s\n", modString);
163getc();
164#else
165msglog("Unable to locate module %s\n", modString);
166#endif
167return EFI_OUT_OF_RESOURCES;
168}
169EFI_STATUS ret = EFI_SUCCESS;
170
171{
172int moduleSize = file_size(fh);
173char* module_base = (char*) malloc(moduleSize);
174if (moduleSize && read(fh, module_base, moduleSize) == moduleSize)
175{
176
177DBG("Module %s read in.\n", modString);
178
179// Module loaded into memory, parse it
180module_start = parse_mach(module_base, &load_module, &add_symbol);
181
182if(module_start && module_start != (void*)0xFFFFFFFF)
183{
184module_loaded(module/*moduleName, moduleVersion, moduleCompat*/);
185// Notify the system that it was laoded
186(*module_start)();// Start the module
187msglog("%s successfully Loaded.\n", module);
188}
189else
190{
191// The module does not have a valid start function
192printf("Unable to start %s\n", module);
193ret = EFI_NOT_STARTED;
194#if DEBUG_MODULES
195getc();
196#endif
197}
198}
199else
200{
201printf("Unable to read in module %s\n.", module);
202#if DEBUG_MODULES
203getc();
204#endif
205ret = EFI_LOAD_ERROR;
206}
207}
208close(fh);
209return ret;
210}
211
212moduleHook_t* get_callback(const char* name)
213{
214moduleHook_t* hooks = moduleCallbacks;
215
216// look for a hook. If it exists, return the moduleHook_t*,
217// If not, return NULL.
218while(hooks)
219{
220if(strcmp(name, hooks->name) == 0)
221{
222//DBG("Located hook %s\n", name);
223return hooks;
224}
225hooks = hooks->next;
226}
227return NULL;
228
229}
230
231/*
232 *execute_hook( const char* name )
233 *name - Name of the module hook
234 *If any callbacks have been registered for this hook
235 *they will be executed now in the same order that the
236 *hooks were added.
237 */
238EFI_STATUS execute_hook(const char* name, void* arg1, void* arg2, void* arg3, void* arg4, void* arg5, void* arg6)
239{
240DBG("Attempting to execute hook '%s'\n", name);
241moduleHook_t* hook = get_callback(name);
242
243if(hook)
244{
245// Loop through all callbacks for this module
246callbackList_t* callbacks = hook->callbacks;
247
248while(callbacks)
249{
250// Execute callback
251callbacks->callback(arg1, arg2, arg3, arg4, arg5, arg6);
252callbacks = callbacks->next;
253}
254DBG("Hook '%s' executed.\n", name);
255return EFI_SUCCESS;
256}
257
258// Callback for this hook doesn't exist;
259DBG("No callbacks for '%s' hook.\n", name);
260return EFI_NOT_FOUND;
261
262}
263
264/*
265 *register_hook_callback( const char* name, void(*callback)())
266 *name - Name of the module hook to attach to.
267 *callbacks - The funciton pointer that will be called when the
268 *hook is executed. When registering a new callback name, the callback is added sorted.
269 *NOTE: the hooks take four void* arguments.
270 */
271VOID register_hook_callback(const char* name, void(*callback)(void*, void*, void*, void*, void*, void*))
272{
273DBG("Adding callback for '%s' hook.\n", name);
274
275moduleHook_t* hook = get_callback(name);
276
277if(hook)
278{
279// append
280callbackList_t* newCallback = malloc(sizeof(callbackList_t));
281newCallback->next = hook->callbacks;
282hook->callbacks = newCallback;
283newCallback->callback = callback;
284}
285else
286{
287// create new hook
288moduleHook_t* newHook = malloc(sizeof(moduleHook_t));
289newHook->name = name;
290newHook->callbacks = malloc(sizeof(callbackList_t));
291newHook->callbacks->callback = callback;
292newHook->callbacks->next = NULL;
293
294newHook->next = moduleCallbacks;
295moduleCallbacks = newHook;
296
297}
298
299#if DEBUG_MODULES
300print_hook_list();
301getc();
302#endif
303
304}
305
306#if DEBUG_MODULES
307unsigned long vmaddr;
308long vmsize;
309#endif
310
311/*
312 * Parse through a macho module. The module will be rebased and binded
313 * as specified in the macho header. If the module is successfully loaded
314 * the module iinit address will be returned.
315 * NOTE; all dependecies will be loaded before this module is started
316 * NOTE: If the module is unable to load ot completeion, the modules
317 * symbols will still be available (TODO: fix this). This should not
318 * happen as all dependencies are verified before the sybols are read in.
319 */
320void* parse_mach(void* binary, EFI_STATUS(*dylib_loader)(char*), long long(*symbol_handler)(char*, long long, char))// TODO: add param to specify valid archs
321{
322char is64 = false;
323void (*module_start)(void) = NULL;
324
325// Module info
326/*char* moduleName = NULL;
327UInt32 moduleVersion = 0;
328UInt32 moduleCompat = 0;
329*/
330
331// TODO convert all of the structs to a union
332struct dyld_info_command* dyldInfoCommand = NULL;
333struct symtab_command* symtabCommand = NULL;
334
335{
336struct segment_command *segCommand = NULL;
337struct segment_command_64 *segCommand64 = NULL;
338struct dylib_command* dylibCommand = NULL;
339struct load_command *loadCommand = NULL;
340UInt32 binaryIndex = 0;
341UInt16 cmd = 0;
342
343// Parse through the load commands
344if(((struct mach_header*)binary)->magic == MH_MAGIC)
345{
346is64 = false;
347binaryIndex += sizeof(struct mach_header);
348}
349else if(((struct mach_header_64*)binary)->magic == MH_MAGIC_64)
350{
351// NOTE: modules cannot be 64bit...
352is64 = true;
353binaryIndex += sizeof(struct mach_header_64);
354}
355else
356{
357printf("Modules: Invalid mach magic\n");
358getc();
359return NULL;
360}
361
362
363
364/*if(((struct mach_header*)binary)->filetype != MH_DYLIB)
365 {
366 printf("Module is not a dylib. Unable to load.\n");
367 getc();
368 return NULL; // Module is in the incorrect format
369 }*/
370
371while(cmd < ((struct mach_header*)binary)->ncmds)
372{
373cmd++;
374
375loadCommand = binary + binaryIndex;
376UInt32 cmdSize = loadCommand->cmdsize;
377
378
379switch ((loadCommand->cmd & 0x7FFFFFFF))
380{
381case LC_SYMTAB:
382symtabCommand = binary + binaryIndex;
383break;
384
385case LC_SEGMENT: // 32bit macho
386{
387segCommand = binary + binaryIndex;
388
389//printf("Segment name is %s\n", segCommand->segname);
390
391if(strcmp("__TEXT", segCommand->segname) == 0)
392{
393UInt32 sectionIndex;
394
395#if HARD_DEBUG_MODULES
396unsigned long fileaddr;
397long filesize;
398vmaddr = (segCommand->vmaddr & 0x3fffffff);
399vmsize = segCommand->vmsize;
400fileaddr = ((unsigned long)(binary + binaryIndex) + segCommand->fileoff);
401filesize = segCommand->filesize;
402
403printf("segname: %s, vmaddr: %x, vmsize: %x, fileoff: %x, filesize: %x, nsects: %d, flags: %x.\n",
404 segCommand->segname, (unsigned)vmaddr, (unsigned)vmsize, (unsigned)fileaddr, (unsigned)filesize,
405 (unsigned) segCommand->nsects, (unsigned)segCommand->flags);
406getc();
407#endif
408sectionIndex = sizeof(struct segment_command);
409
410struct section *sect;
411
412while(sectionIndex < segCommand->cmdsize)
413{
414sect = binary + binaryIndex + sectionIndex;
415
416sectionIndex += sizeof(struct section);
417
418
419if(strcmp("__text", sect->sectname) == 0)
420{
421// __TEXT,__text found, save the offset and address for when looking for the calls.
422textSection = sect->offset;
423textAddress = sect->addr;
424break;
425}
426}
427}
428break;
429}
430case LC_SEGMENT_64:// 64bit macho's
431{
432segCommand64 = binary + binaryIndex;
433
434//printf("Segment name is %s\n", segCommand->segname);
435
436if(strcmp("__TEXT", segCommand64->segname) == 0)
437{
438UInt32 sectionIndex;
439
440#if HARD_DEBUG_MODULES
441
442unsigned long fileaddr;
443long filesize;
444vmaddr = (segCommand64->vmaddr & 0x3fffffff);
445vmsize = segCommand64->vmsize;
446fileaddr = ((unsigned long)(binary + binaryIndex) + segCommand64->fileoff);
447filesize = segCommand64->filesize;
448
449printf("segname: %s, vmaddr: %x, vmsize: %x, fileoff: %x, filesize: %x, nsects: %d, flags: %x.\n",
450 segCommand64->segname, (unsigned)vmaddr, (unsigned)vmsize, (unsigned)fileaddr, (unsigned)filesize,
451 (unsigned) segCommand64->nsects, (unsigned)segCommand64->flags);
452getc();
453#endif
454
455sectionIndex = sizeof(struct segment_command_64);
456
457struct section_64 *sect;
458
459while(sectionIndex < segCommand64->cmdsize)
460{
461sect = binary + binaryIndex + sectionIndex;
462
463sectionIndex += sizeof(struct section_64);
464
465
466if(strcmp("__text", sect->sectname) == 0)
467{
468// __TEXT,__text found, save the offset and address for when looking for the calls.
469textSection = sect->offset;
470textAddress = sect->addr;
471
472break;
473}
474}
475}
476
477break;
478}
479case LC_DYSYMTAB:
480break;
481
482case LC_LOAD_DYLIB:
483case LC_LOAD_WEAK_DYLIB ^ LC_REQ_DYLD:
484{
485dylibCommand = binary + binaryIndex;
486char* module = binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
487// TODO: verify version
488// =dylibCommand->dylib.current_version;
489// =dylibCommand->dylib.compatibility_version;
490char* name = malloc(strlen(module) + strlen(".dylib") + 1);
491sprintf(name, "%s.dylib", module);
492if(dylib_loader == EFI_SUCCESS)
493{
494EFI_STATUS statue = dylib_loader(name);
495
496if( statue != EFI_SUCCESS)
497{
498free(name);
499if (statue != EFI_ALREADY_STARTED)
500{
501// Unable to load dependancy
502return NULL;
503}
504
505}
506
507}
508break;
509}
510case LC_ID_DYLIB:
511dylibCommand = binary + binaryIndex;
512/*moduleName =binary + binaryIndex + ((UInt32)*((UInt32*)&dylibCommand->dylib.name));
513 moduleVersion =dylibCommand->dylib.current_version;
514 moduleCompat =dylibCommand->dylib.compatibility_version;
515 */
516break;
517
518case LC_DYLD_INFO:
519// Bind and rebase info is stored here
520dyldInfoCommand = binary + binaryIndex;
521break;
522
523case LC_UUID:
524break;
525
526case LC_UNIXTHREAD:
527break;
528
529default:
530DBG("Unhandled loadcommand 0x%X\n", loadCommand->cmd & 0x7FFFFFFF);
531break;
532
533}
534
535binaryIndex += cmdSize;
536}
537//if(!moduleName) return NULL;
538}
539
540// bind_macho uses the symbols.
541module_start = (void*)handle_symtable((UInt32)binary, symtabCommand, symbol_handler, is64);
542
543// Rebase the module before binding it.
544if(dyldInfoCommand && dyldInfoCommand->rebase_off)
545{
546rebase_macho(binary, (char*)dyldInfoCommand->rebase_off, dyldInfoCommand->rebase_size);
547}
548
549if(dyldInfoCommand && dyldInfoCommand->bind_off)
550{
551bind_macho(binary, (char*)dyldInfoCommand->bind_off, dyldInfoCommand->bind_size);
552}
553
554if(dyldInfoCommand && dyldInfoCommand->weak_bind_off)
555{
556// NOTE: this currently should never happen.
557bind_macho(binary, (char*)dyldInfoCommand->weak_bind_off, dyldInfoCommand->weak_bind_size);
558}
559
560if(dyldInfoCommand && dyldInfoCommand->lazy_bind_off)
561{
562// NOTE: we are binding the lazy pointers as a module is laoded,
563// This should be changed to bind when a symbol is referened at runtime instead.
564bind_macho(binary, (char*)dyldInfoCommand->lazy_bind_off, dyldInfoCommand->lazy_bind_size);
565}
566
567return module_start;
568
569}
570
571// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
572void rebase_macho(void* base, char* rebase_stream, UInt32 size)
573{
574rebase_stream += (UInt32)base;
575
576UInt8 immediate = 0;
577UInt8 opcode = 0;
578UInt8 type = 0;
579
580UInt32 segmentAddress = 0;
581
582
583
584UInt32 tmp = 0;
585UInt32 tmp2 = 0;
586UInt8 bits = 0;
587UInt32 index = 0;
588
589int done = 0;
590unsigned int i = 0;
591
592while(/*!done &&*/ i < size)
593{
594immediate = rebase_stream[i] & REBASE_IMMEDIATE_MASK;
595opcode = rebase_stream[i] & REBASE_OPCODE_MASK;
596
597
598switch(opcode)
599{
600case REBASE_OPCODE_DONE:
601// Rebase complete.
602done = 1;
603break;
604
605
606case REBASE_OPCODE_SET_TYPE_IMM:
607// Set rebase type (pointer, absolute32, pcrel32)
608//DBG("Rebase type = 0x%X\n", immediate);
609type = immediate;
610break;
611
612
613case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
614{
615// Locate address to begin rebasing
616segmentAddress = 0;
617
618struct segment_command* segCommand = NULL; // NOTE: 32bit only
619
620{
621unsigned int binIndex = 0;
622index = 0;
623do
624{
625segCommand = base + sizeof(struct mach_header) + binIndex;
626
627
628binIndex += segCommand->cmdsize;
629index++;
630}
631while(index <= immediate);
632}
633
634segmentAddress = segCommand->fileoff;
635
636tmp = 0;
637bits = 0;
638do
639{
640tmp |= (rebase_stream[++i] & 0x7f) << bits;
641bits += 7;
642}
643while(rebase_stream[i] & 0x80);
644
645segmentAddress += tmp;
646break;
647}
648case REBASE_OPCODE_ADD_ADDR_ULEB:
649// Add value to rebase address
650tmp = 0;
651bits = 0;
652do
653{
654tmp <<= bits;
655tmp |= rebase_stream[++i] & 0x7f;
656bits += 7;
657}
658while(rebase_stream[i] & 0x80);
659
660segmentAddress +=tmp;
661break;
662
663case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
664segmentAddress += immediate * sizeof(void*);
665break;
666
667
668case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
669index = 0;
670for (index = 0; index < immediate; ++index)
671{
672rebase_location(base + segmentAddress, (char*)base, type);
673segmentAddress += sizeof(void*);
674}
675break;
676
677
678case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
679tmp = 0;
680bits = 0;
681do
682{
683tmp |= (rebase_stream[++i] & 0x7f) << bits;
684bits += 7;
685}
686while(rebase_stream[i] & 0x80);
687
688index = 0;
689for (index = 0; index < tmp; ++index)
690{
691//DBG("\tRebasing 0x%X\n", segmentAddress);
692rebase_location(base + segmentAddress, (char*)base, type);
693segmentAddress += sizeof(void*);
694}
695break;
696
697case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
698tmp = 0;
699bits = 0;
700do
701{
702tmp |= (rebase_stream[++i] & 0x7f) << bits;
703bits += 7;
704}
705while(rebase_stream[i] & 0x80);
706
707rebase_location(base + segmentAddress, (char*)base, type);
708
709segmentAddress += tmp + sizeof(void*);
710break;
711
712case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
713tmp = 0;
714bits = 0;
715do
716{
717tmp |= (rebase_stream[++i] & 0x7f) << bits;
718bits += 7;
719}
720while(rebase_stream[i] & 0x80);
721
722
723tmp2 = 0;
724bits = 0;
725do
726{
727tmp2 |= (rebase_stream[++i] & 0x7f) << bits;
728bits += 7;
729}
730while(rebase_stream[i] & 0x80);
731
732index = 0;
733for (index = 0; index < tmp; ++index)
734{
735
736rebase_location(base + segmentAddress, (char*)base, type);
737
738segmentAddress += tmp2 + sizeof(void*);
739}
740break;
741default:
742break;
743}
744i++;
745}
746}
747
748// Based on code from dylibinfo.cpp and ImageLoaderMachOCompressed.cpp
749// NOTE: this uses 32bit values, and not 64bit values.
750// There is apossibility that this could cause issues,
751// however the macho file is 32 bit, so it shouldn't matter too much
752void bind_macho(void* base, char* bind_stream, UInt32 size)
753{
754bind_stream += (UInt32)base;
755
756UInt8 immediate = 0;
757UInt8 opcode = 0;
758UInt8 type = 0;
759
760UInt32 segmentAddress = 0;
761
762UInt32 address = 0;
763
764SInt32 addend = 0;// TODO: handle this
765SInt32 libraryOrdinal = 0;
766
767const char* symbolName = NULL;
768UInt8 symboFlags = 0;
769UInt32 symbolAddr = 0xFFFFFFFF;
770
771// Temperary variables
772UInt8 bits = 0;
773UInt32 tmp = 0;
774UInt32 tmp2 = 0;
775
776UInt32 index = 0;
777int done = 0;
778unsigned int i = 0;
779
780while(/*!done &&*/ i < size)
781{
782immediate = bind_stream[i] & BIND_IMMEDIATE_MASK;
783opcode = bind_stream[i] & BIND_OPCODE_MASK;
784
785
786switch(opcode)
787{
788case BIND_OPCODE_DONE:
789done = 1;
790break;
791
792case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
793libraryOrdinal = immediate;
794//DBG("BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: %d\n", libraryOrdinal);
795break;
796
797case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
798libraryOrdinal = 0;
799bits = 0;
800do
801{
802libraryOrdinal |= (bind_stream[++i] & 0x7f) << bits;
803bits += 7;
804}
805while(bind_stream[i] & 0x80);
806
807//DBG("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: %d\n", libraryOrdinal);
808
809break;
810
811case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
812// NOTE: this is wrong, fortunately we don't use it
813libraryOrdinal = -immediate;
814//DBG("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: %d\n", libraryOrdinal);
815
816break;
817
818case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
819symboFlags = immediate;
820symbolName = (char*)&bind_stream[++i];
821i += strlen((char*)&bind_stream[i]);
822//DBG("BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: %s, 0x%X\n", symbolName, symboFlags);
823
824symbolAddr = lookup_all_symbols(symbolName);
825
826break;
827
828case BIND_OPCODE_SET_TYPE_IMM:
829// Set bind type (pointer, absolute32, pcrel32)
830type = immediate;
831//DBG("BIND_OPCODE_SET_TYPE_IMM: %d\n", type);
832
833break;
834
835case BIND_OPCODE_SET_ADDEND_SLEB:
836addend = 0;
837bits = 0;
838do
839{
840addend |= (bind_stream[++i] & 0x7f) << bits;
841bits += 7;
842}
843while(bind_stream[i] & 0x80);
844
845if(!(bind_stream[i-1] & 0x40)) addend *= -1;
846
847//DBG("BIND_OPCODE_SET_ADDEND_SLEB: %d\n", addend);
848break;
849
850case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
851{
852segmentAddress = 0;
853
854// Locate address
855struct segment_command* segCommand = NULL;// NOTE: 32bit only
856
857{
858unsigned int binIndex = 0;
859index = 0;
860do
861{
862segCommand = base + sizeof(struct mach_header) + binIndex;
863binIndex += segCommand->cmdsize;
864index++;
865}while(index <= immediate);
866}
867
868
869segmentAddress = segCommand->fileoff;
870
871// Read in offset
872tmp = 0;
873bits = 0;
874do
875{
876tmp |= (bind_stream[++i] & 0x7f) << bits;
877bits += 7;
878}while(bind_stream[i] & 0x80);
879
880segmentAddress += tmp;
881
882//DBG("BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: 0x%X\n", segmentAddress);
883break;
884}
885case BIND_OPCODE_ADD_ADDR_ULEB:
886// Read in offset
887tmp = 0;
888bits = 0;
889do
890{
891tmp |= (bind_stream[++i] & 0x7f) << bits;
892bits += 7;
893}
894while(bind_stream[i] & 0x80);
895
896segmentAddress += tmp;
897//DBG("BIND_OPCODE_ADD_ADDR_ULEB: 0x%X\n", segmentAddress);
898break;
899
900case BIND_OPCODE_DO_BIND:
901//DBG("BIND_OPCODE_DO_BIND\n");
902if(symbolAddr != 0xFFFFFFFF)
903{
904address = segmentAddress + (UInt32)base;
905
906bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
907}
908else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
909{
910printf("Unable to bind symbol %s\n", symbolName);
911 getc();
912}
913
914segmentAddress += sizeof(void*);
915break;
916
917case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
918//DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB\n");
919
920
921// Read in offset
922tmp = 0;
923bits = 0;
924do
925{
926tmp |= (bind_stream[++i] & 0x7f) << bits;
927bits += 7;
928}
929while(bind_stream[i] & 0x80);
930
931
932
933if(symbolAddr != 0xFFFFFFFF)
934{
935address = segmentAddress + (UInt32)base;
936
937bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
938}
939else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
940{
941printf("Unable to bind symbol %s\n", symbolName);
942}
943segmentAddress += tmp + sizeof(void*);
944
945
946break;
947
948case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
949//DBG("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED\n");
950
951if(symbolAddr != 0xFFFFFFFF)
952{
953address = segmentAddress + (UInt32)base;
954
955bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
956}
957else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
958{
959printf("Unable to bind symbol %s\n", symbolName);
960}
961segmentAddress += (immediate * sizeof(void*)) + sizeof(void*);
962
963
964break;
965
966case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
967
968tmp = 0;
969bits = 0;
970do
971{
972tmp |= (bind_stream[++i] & 0x7f) << bits;
973bits += 7;
974}
975while(bind_stream[i] & 0x80);
976
977
978tmp2 = 0;
979bits = 0;
980do
981{
982tmp2 |= (bind_stream[++i] & 0x7f) << bits;
983bits += 7;
984}
985while(bind_stream[i] & 0x80);
986
987
988//DBG("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0x%X 0x%X\n", tmp, tmp2);
989
990
991if(symbolAddr != 0xFFFFFFFF)
992{
993for(index = 0; index < tmp; index++)
994{
995
996address = segmentAddress + (UInt32)base;
997
998bind_location((UInt32*)address, (char*)symbolAddr, addend, BIND_TYPE_POINTER);
999
1000segmentAddress += tmp2 + sizeof(void*);
1001}
1002}
1003else if(strcmp(symbolName, SYMBOL_DYLD_STUB_BINDER) != 0)
1004{
1005printf("Unable to bind symbol %s\n", symbolName);
1006}
1007
1008
1009break;
1010default:
1011break;
1012
1013}
1014i++;
1015}
1016}
1017
1018inline void rebase_location(UInt32* location, char* base, int type)
1019{
1020switch(type)
1021{
1022case REBASE_TYPE_POINTER:
1023case REBASE_TYPE_TEXT_ABSOLUTE32:
1024*location += (UInt32)base;
1025break;
1026
1027default:
1028break;
1029}
1030}
1031
1032inline void bind_location(UInt32* location, char* value, UInt32 addend, int type)
1033{
1034// do actual update
1035char* newValue = value + addend;
1036
1037switch (type) {
1038case BIND_TYPE_POINTER:
1039case BIND_TYPE_TEXT_ABSOLUTE32:
1040break;
1041
1042case BIND_TYPE_TEXT_PCREL32:
1043newValue -= ((UInt32)location + 4);
1044
1045break;
1046default:
1047return;
1048}
1049*location = (UInt32)newValue;
1050
1051
1052}
1053
1054/*
1055 * add_symbol
1056 * This function adds a symbol from a module to the list of known symbols
1057 * possibly change to a pointer and add this to the Symbol module so that it can
1058 * adjust it's internal symbol list (sort) to optimize locating new symbols
1059 * NOTE: returns the address if the symbol is "start", else returns 0xFFFFFFFF
1060 */
1061long long add_symbol(char* symbol, long long addr, char is64)
1062{
1063if(is64) return 0xFFFFFFFF; // Fixme
1064
1065// This only can handle 32bit symbols
1066symbolList_t* new_entry= malloc(sizeof(symbolList_t));
1067DBG("Adding symbol %s at 0x%X\n", symbol, addr);
1068if (new_entry)
1069{
1070new_entry->next = moduleSymbols;
1071
1072moduleSymbols = new_entry;
1073
1074new_entry->addr = (UInt32)addr;
1075new_entry->symbol = symbol;
1076return addr;
1077}
1078
1079return 0xFFFFFFFF;
1080
1081}
1082
1083/*
1084 * print out the information about the loaded module
1085 */
1086VOID module_loaded(const char* name/*, UInt32 version, UInt32 compat*/)
1087{
1088moduleList_t* new_entry = malloc(sizeof(moduleList_t));
1089if (new_entry)
1090{
1091new_entry->next = loadedModules;
1092
1093loadedModules = new_entry;
1094
1095new_entry->module = (char*)name;
1096//new_entry->version = version;
1097//new_entry->compat = compat;
1098}
1099}
1100
1101EFI_STATUS is_module_loaded(const char* name)
1102{
1103moduleList_t* entry = loadedModules;
1104while(entry)
1105{
1106DBG("Comparing %s with %s\n", name, entry->module);
1107char fullname[128];
1108sprintf(fullname, "%s.dylib",name);
1109if((strcmp(entry->module, name) == 0) || (strcmp(entry->module, fullname) == 0))
1110{
1111DBG("Located module %s\n", name);
1112return EFI_SUCCESS;
1113}
1114else
1115{
1116entry = entry->next;
1117}
1118
1119}
1120DBG("Module %s not found\n", name);
1121
1122return EFI_NOT_FOUND;
1123}
1124
1125// Look for symbols using the Smbols moduel function.
1126// If non are found, look through the list of module symbols
1127unsigned int lookup_all_symbols(const char* name)
1128{
1129{
1130unsigned int addr = 0xFFFFFFFF;
1131if(lookup_symbol && (UInt32)lookup_symbol != 0xFFFFFFFF)
1132{
1133addr = lookup_symbol(name);
1134if(addr != 0xFFFFFFFF)
1135{
1136DBG("Internal symbol %s located at 0x%X\n", name, addr);
1137return addr;
1138}
1139}
1140}
1141
1142{
1143symbolList_t* entry = moduleSymbols;
1144while(entry)
1145{
1146if(strcmp(entry->symbol, name) == 0)
1147{
1148DBG("External symbol %s located at 0x%X\n", name, entry->addr);
1149return entry->addr;
1150}
1151else
1152{
1153entry = entry->next;
1154}
1155
1156}
1157}
1158
1159#if DEBUG_MODULES
1160if(strcmp(name, SYMBOL_DYLD_STUB_BINDER) != 0)
1161{
1162verbose("Unable to locate symbol %s\n", name);
1163getc();
1164}
1165#endif
1166return 0xFFFFFFFF;
1167}
1168
1169
1170/*
1171 * parse the symbol table
1172 * Lookup any undefined symbols
1173 */
1174
1175unsigned int handle_symtable(UInt32 base, struct symtab_command* symtabCommand, long long(*symbol_handler)(char*, long long, char), char is64)
1176{
1177unsigned int module_start = 0xFFFFFFFF;
1178
1179UInt32 symbolIndex = 0;
1180char* symbolString = base + (char*)symtabCommand->stroff;
1181//char* symbolTable = base + symtabCommand->symoff;
1182if(!is64)
1183{
1184struct nlist* symbolEntry = (void*)base + symtabCommand->symoff;
1185while(symbolIndex < symtabCommand->nsyms)
1186{
1187if(symbolEntry->n_value)
1188{
1189if(strcmp(symbolString + symbolEntry->n_un.n_strx, "start") == 0)
1190{
1191// Module start located. 'start' is an alias so don't register it
1192module_start = base + symbolEntry->n_value;
1193DBG("n_value %x module_start %x\n", (unsigned)symbolEntry->n_value, (unsigned)module_start);
1194}
1195else
1196{
1197symbol_handler(symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64);
1198}
1199
1200#if HARD_DEBUG_MODULES
1201bool isTexT = (((unsigned)symbolEntry->n_value > (unsigned)vmaddr) && ((unsigned)(vmaddr + vmsize) > (unsigned)symbolEntry->n_value ));
1202printf("%s %s\n", isTexT ? "__TEXT :" : "__DATA(OR ANY) :", symbolString + symbolEntry->n_un.n_strx);
1203
1204if(strcmp(symbolString + symbolEntry->n_un.n_strx, "_BootHelp_txt") == 0)
1205{
1206long long addr = (long long)base + symbolEntry->n_value;
1207unsigned char *BootHelp = NULL;
1208BootHelp = (unsigned char*)(UInt32)addr;
1209printf("method 1: __DATA : BootHelp_txt[0] %x\n", BootHelp[0]);
1210
1211long long addr2 = symbolEntry->n_value;
1212unsigned char *BootHelp2 = NULL;
1213BootHelp2 = (unsigned char*)(UInt32)addr2;
1214printf("method 2: __DATA : BootHelp_txt[0] %x\n", BootHelp2[0]);
1215}
1216#endif
1217}
1218
1219symbolEntry++;
1220symbolIndex++;// TODO remove
1221}
1222}
1223else
1224{
1225struct nlist_64* symbolEntry = (void*)base + symtabCommand->symoff;
1226// NOTE First entry is *not* correct, but we can ignore it (i'm getting radar:// right now)
1227while(symbolIndex < symtabCommand->nsyms)
1228{
1229
1230if(strcmp(symbolString + symbolEntry->n_un.n_strx, "start") == 0)
1231{
1232// Module start located. 'start' is an alias so don't register it
1233module_start = base + symbolEntry->n_value;
1234}
1235else
1236{
1237symbol_handler(symbolString + symbolEntry->n_un.n_strx, (long long)base + symbolEntry->n_value, is64);
1238}
1239
1240symbolEntry++;
1241symbolIndex++;// TODO remove
1242}
1243}
1244
1245return module_start;
1246
1247}
1248
1249
1250/*
1251 * Locate the symbol for an already loaded function and modify the beginning of
1252 * the function to jump directly to the new one
1253 * example: replace_function("_HelloWorld_start", &replacement_start);
1254 */
1255EFI_STATUS replace_function(const char* symbol, void* newAddress)
1256{
1257// TODO: look into using the next four bytes of the function instead
1258// Most functions should support this, as they probably will be at
1259// least 10 bytes long, but you never know, this is sligtly safer as
1260// function can be as small as 6 bytes.
1261UInt32 addr = lookup_all_symbols(symbol);
1262
1263char* binary = (char*)addr;
1264if(addr != 0xFFFFFFFF)
1265{
1266UInt32* jumpPointer = malloc(sizeof(UInt32*));
1267
1268*binary++ = 0xFF;// Jump
1269*binary++ = 0x25;// Long Jump
1270*((UInt32*)binary) = (UInt32)jumpPointer;
1271
1272*jumpPointer = (UInt32)newAddress;
1273
1274return EFI_SUCCESS;
1275}
1276
1277return EFI_NOT_FOUND;
1278
1279}
1280
1281
1282/* Nedded to divide 64bit numbers correctly. TODO: look into why modules need this
1283 * And why it isn't needed when compiled into boot2
1284 *
1285 * In the next versions, this will be surely replaced by the Apple's libcc_kext or the meklort's klibc
1286 */
1287
1288uint64_t __udivdi3(uint64_t numerator, uint64_t denominator)
1289{
1290uint64_t quotient = 0, qbit = 1;
1291
1292if (denominator)
1293{
1294while ((int64_t) denominator >= 0)
1295{
1296denominator <<= 1;
1297qbit <<= 1;
1298}
1299
1300while (denominator)
1301{
1302if (denominator <= numerator)
1303{
1304numerator -= denominator;
1305quotient += qbit;
1306}
1307denominator >>= 1;
1308qbit >>= 1;
1309}
1310
1311return quotient;
1312}
1313
1314stop("Divide by 0");
1315return 0;
1316}
1317

Archive Download this file

Revision: 1654