Автор/Источник: Ронин Виктор» 12.11.2002 15:53, просмотров сегодня: 1, всего: 2703
статья размещена в группе: Программирование
оценка: 5, 2 голоса
Перед тем, как перейти непосредственно к рассмотрению
устройства Shared Library, сделаем небольшой экскурс в структуру PalmOS, на уровне ассемблерного кода. Вызов любой API функции в ассемблерном виде выглядит так.
trap #15
SYSTEM_TRAP_NUMBER
Для каждой новой библиотеки система не может выделять новые
номера trap’ов и прописывать их обработчики. Это связано с тем,
что в таком случае таблица обработчиков trap’ов должна была бы динамически изменяться, программы использующие Lib’ы должны были динамически подставлять номер trap’ов, который им надо вызвать и д.р. Как результат для библиотек были выделены фиктивные trap’ы начинающиеся с 0xA800. Фиктивными они являются потому, что, на самом деле, адреса обработчиков функций Lib’ы не хранят в той же таблице, что и адреса обработчиков функций API, а также из-за того, что всем trap’ам с номером большим 0xA800 присвоен один единственный обработчик, который dispatch’ит вызов нужной библиотеке и нужной функции.
Начинается он с вызова
функции SysLibLoad, которая ищет соответствующую .prс, и если
prc найдена, то открывает в ней ’libr’ ресурс и передает
ему управления вместе с параметрами refNum и SysLibTblEntryPtr.
В системе храниться таблица для всех загруженных Shared Librarys,
которая индексируется по refNum и состоит из SysLibTblEntryType.
Так вот, функция SysLibLoad, а точнее функции SysLibInstall,
которую она вызывает, находит в таблице свободный refNum, инициализирует начальными значениями структуру в этой таблице. После чего refNum и указатель на структуру(SysLibTblEntryPtr) передаются паараметрами в функцию, которая является точкой входа (Entry Point) в библиотеку.
Вот стандартная Entry Point для функции:
Err SampleLibInstall(UInt16 refNum, SysLibTblEntryPtr entryP)
{
// Install pointer to our dispatch table
entryP->dispatchTblP = (MemPtr*)SampleLibDispatchTable();
// Initialize globals pointer to zero (we will set up our library
// globals in the library «open» call).
entryP->globalsP = 0;
return 0;
}
static MemPtr asm SampleLibDispatchTable(void)
{
LEA @Table, A0 // table ptr
RTS // exit with it
@Table:
// Offset to library name
DC.W @Name
//
// Library function dispatch entries
//
// ***IMPORTANT***
// The index parameters passed to the macro libDispatchEntry
// must be numbered consecutively, beginning with zero.
//
// The hard-wired values need to be used for offsets because the MW SDK tools do
// not support label subtraction.
//
// Standard traps
DC.W libDispatchEntry(0) // Open
DC.W libDispatchEntry(1) // Close
DC.W libDispatchEntry(2) // Sleep
DC.W libDispatchEntry(3) // Wake
// Start of the Custom traps
DC.W libDispatchEntry(4) // GetLibAPIVersion
DC.W libDispatchEntry(5) // SetCornerDiameter
DC.W libDispatchEntry(6) // GetCornerDiameter
DC.W libDispatchEntry(7) // DrawRectangle
// Standard library function handlers
@GotoOpen:
JMP SampleLibOpen
@GotoClose:
JMP SampleLibClose
@GotoSleep:
JMP SampleLibSleep
@GotoWake:
JMP SampleLibWake
// Customer library function handlers
@GotoGetLibAPIVersion:
JMP SampleLibGetLibAPIVersion
@GotoSetCornerDiameter:
JMP SampleLibSetCornerDiameter
@GotoGetCornerDiameter:
JMP SampleLibGetCornerDiameter
@GotoDrawRectangle:
JMP SampleLibDrawRectangle
@Name:
// This name identifies the library. Apps
DC.B sampleLibName
}
При любом вызове этой функции библиотеки из программы, будет вызван trap 0xA8xx, где xx какое-то число. Управление получит обработчик trap #15 он его передаст dispatch’еру вызовов к Shared Librarys (так как trap > 0xA800). Далее этот dispatch’ер по refNum’у получит SysLibTblEntryPtr из таблицы
Shared Librarys. RefNum он получает из стека, так как каждой функции из Shared Library первым параметром должен передаваться ее refNum. После получения SysLibTblEntryPtr dispatch’ер берет из него таблицу dispatch’а внутри библиотеки, и получив разницу между номером Trap’а который был вызван и 0xA800 извлекает из этой таблицы адрес функции в библиотеки, после чего передает ей управление.
По окончанию работы с библиотекой вызывает функция SysLibRemove, которая отчищает запись в таблице Shared Librarys, соответствующую переданному refNum’у.
typedef enum {
sampleLibTrapGetLibAPIVersion = sysLibTrapCustom,
sampleLibTrapSetCornerDiameter,
sampleLibTrapGetCornerDiameter,
sampleLibTrapDrawRectangle,
sampleLibTrapLast
} SampleLibTrapNumberEnum;
extern Err SampleLibOpen(UInt16 refNum, UInt32 * clientContextP)
SAMPLE_LIB_TRAP(sysLibTrapOpen);
#ifdef BUILDING_SAMPLE_LIB
#define SAMPLE_LIB_TRAP(trapNum)
#else
#define SAMPLE_LIB_TRAP(trapNum) SYS_TRAP(trapNum)
#endif
#define SampleLibInstall __Startup__
|