Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 583