Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 639