Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 655