Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 636