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

Archive Download this file

Revision: 1136