Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 649