// структура и прототип взяты из sdk от mobile-stream typedef struct { UInt32 dbType; UInt32 dbCreator; UInt32 revision; UInt32 entries; UInt32 rsrcTypeData0; UInt32 rsrcTypeCode0; UInt32 rsrcTypeCode1; UInt16 rsrcIDData0; UInt16 rsrcIDCode0; UInt16 rsrcIDCode1; UInt16 reserved; } SysModuleDescriptorType; void SysLinkerStub(const SysModuleDescriptorType *moduleP, UInt32 clientID, void **dispatchTablePP); /* * Вызов процедуры при неявном связывании происходит в три этапа. Инфраструктуру * строит специальный препроцессор, используя библиотеку экспорта библиотеки. * Каждый этап является законченным фрагментом кода. Первый фрагмент генерируется * для каждой функции, второй - для каждой билиотеки, а третий - один на все вызовы. * * Неявное связывание происходит при первом вызове функции из модуля. Этот вызов загружает * библиотеку и записывает в определенное место в памяти адрес таблицы экспорта. * Все последующие вызовы вызывают функции напрямую. * * Список модифицируемых команд в функциях * 1. В ExportedFunction1 * 1.1 LDR R12, [R12,#CURRENT_MODULE_INDEX] * вписывается индекс текущего модуля * 1.2 LDR R12, [R12,#LIB1_DISPATCH_ADDRESS_OFFSET_IN_GLOBALS] * вписывается смещение глобальной переменной с адресом таблицы экспорта * 1.3 ADDNE PC, R12, #EXPORTED_FUNCTION1_ORDINAL * вписывается смещение функции в таблице экспорта (номер функции * 4) * 2. В LoadLib1 * 2.1 Формируется структура lib1Desc * 3. В функции ImplicitLoadLibrary * 3.1 LDR R2, [R2,#CURRENT_MODULE_INDEX] * вписывается индекс текущего модуля */ #define CURRENT_MODULE_INDEX 0x200 #define LIB1_DISPATCH_ADDRESS_OFFSET_IN_GLOBALS 0x10 #define EXPORTED_FUNCTION1_OFFSET (20 * 4) Err ExportedFunction1(UInt32 param0, UInt32 param1, UInt32 param2, UInt32 param3, UInt32 param4, UInt32 param5, UInt32 param6){ // загрузить в R12 указатель на сегмент данных используемого модуля _asm LDR R12, [R9] ExportedFunction1_LabelWithCurrentModuleIndexAddr: _asm LDR R12, [R12,#CURRENT_MODULE_INDEX] ExportedFunction1_LabelWithDispatchAddr: // загрузить в R12 адрес таблицы экспорта вызываемого модуля _asm LDR R12, [R12,#LIB1_DISPATCH_ADDRESS_OFFSET_IN_GLOBALS] // проверить, что библиотека уже загружена (адрес != 0), _asm CMP R12, #0 // если билиотека загружена, то перейти на функцию по смещению в библиотеке _asm ADDNE PC, R12, #EXPORTED_FUNCTION1_OFFSET // если функция не загружена, то перейти ко второй фазе, // предварительно сохранив в стеке адрес метки ExportedFunction1_Addr // для повторного вызова после загрузки библиотеки _asm STMFD SP!, {PC} _asm B LoadLib1 ExportedFunction1_BackAddr: } Err LoadLib1(UInt32 param0, UInt32 param1, UInt32 param2, UInt32 param3, UInt32 param4, UInt32 *backAddr, UInt32 param5, UInt32 param6){ _asm ADR R12, lib1Desc _asm STMFD SP!, {R12} _asm B ImplicitLoadLibrary } // константный дескриптор следует в коде сразу после функции const SysModuleDescriptorType lib1Desc = {'aexo', 'HsEx', 1, 0x6E, 'amdd', 'amdi', 'amdc', 0, 0, 0, 0}; Err ImplicitLoadLibrary(UInt32 param0, UInt32 param1, UInt32 param2, UInt32 param3, UInt32 param4, SysModuleDescriptorType *pDescr, UInt32 *backAddr, UInt32 param5, UInt32 param6){ /* сохранить регистры. * после операции в стеке располагаются: * SP + 00 R0 * SP + 04 R1 * SP + 08 R2 * SP + 0C R3 * SP + 10 LR * SP + 14 pDescr * SP + 18 backAddr * SP + 1C param5 * SP + 20 param6 */ _asm STMFD SP!, {R0-R3,LR} // R1 = ImplicitLoadLibrary_Label0 (ImplicitLoadLibrary_Label1 - 4) _asm SUB R1, PC, #4 // R2 = ImplicitLoadLibrary_Label2 ImplicitLoadLibrary_Label0: _asm STMFD SP!, {PC} ImplicitLoadLibrary_Label1: _asm LDMFD SP!, {R2} ImplicitLoadLibrary_Label2: // R2 = ImplicitLoadLibrary_Label2 - ImplicitLoadLibrary_Label0 + 0x14 (0x1C) _asm SUB R2, R2, R1 _asm ADD R2, R2, #0x14 // *backAddr -= ImplicitLoadLibrary_Label2 - ImplicitLoadLibrary_Label0 + 0x14 (0x1C) // скорректировать backAddr дабы он указывал на ExportedFunction1 _asm LDR R1, [SP,#0x18] _asm SUB R1, R1, R2 _asm STR R1, [SP,#0x18] // R0 = *(ExportedFunction1_LabelWithDispatchAddr) // R0 = "LDR R12, [R12,#LIB1_DISPATCH_ADDRESS_OFFSET_IN_GLOBALS]" _asm LDR R0, [R1,#8] // R3 = 0xFFF _asm MOV R3, #0x1000 _asm SUB R3, R3, #1 // R0 = LIB1_DISPATCH_ADDRESS_OFFSET_IN_GLOBALS _asm AND R0, R0, R3 // загрузить в R12 указатель на сегмент данных используемого модуля _asm LDR R2, [R9] _asm LDR R2, [R2,#CURRENT_MODULE_INDEX] // загрузить в R2 адрес таблицы экспорта вызываемого модуля _asm ADD R2, R2, R0 // R0 = *ExportedFunction1_LabelWithCurrentModuleIndexAddr // R0 = "LDR R12, [R12,#CURRENT_MODULE_INDEX]" _asm LDR R0, [R1,#4] // R1 = CURRENT_MODULE_INDEX / 4 _asm AND R1, R0, R3 _asm MOV R1, R1,LSR#2 _asm LDR R0, [SP,#0x14] _asm BL SysLinkerStub // восстановить регистры _asm LDMFD SP!, {R0-R3,LR} // выкинуть из стека pDescr _asm LDMFD SP!, {R12} // R12 = backAddr _asm LDMFD SP!, {R12} // перейти на backAddr _asm MOV PC, R12 }