Palm Notes | Recent Changes | Title Index | User Preferences | Random Page | Help
Difference from prior author
revision.
major diff minor diff hide diffСтатья
объясняет
идеологию
мультисегментных приложений для PalmOS с использованием GCC.
В
информатике
существует
малоизвестный термин ABI - Application Binary Interface. Этим термином называют набор особенностей компьютерной архитектуры, которые нужно учитывать при создании приложения. ABI может накладываться процессором: направление роста стека, размер элемента данных в стеке, порядок байт в слове итд. Также ABI может накладываться операционной системой. Тогда в ABI входит способ вызова системного API, специфика использования адресного пространства и прочие нюансы. Изменения, которые вносятся в GCC для компиляции под PalmOS, нужны именно для соответствия PalmOS ABI.
Что такое
приложение с
точки зрения
PalmOS? Приложение
- это база
ресурсов.
Четыре
ресурса из
этой базы
используются для исполнения программы.
Это ресурс 'code' #1,
в котором
собственно и
хранится
исполняемый
код, который
запускается
с нулевого
байта
ресурса.
Также из
ресурса 'code' #0
берется
размеры
области
глобальных
данных. Из
ресурса 'pref' #0
берется
размер стека.
И ресурс 'data' #0
используется
для
инициализации
глобальных
данных. Все!
До всего
остального
содержимого
базы
приложения PalmOS
дела нет.
Подробности
можно
почитать
здесь:
http://www.linuxmafia.com/pub/palmos/development/prc-format.html
Такой способ
позволяет
запускать
программы
практически
"на месте",
выделяя
только
память под
стек и
глобальные
переменные.
Какие
ограничения
накладываются на простое односегментное приложение?
1 * Размер
ресурса 'code' #0
2 dd ограничен
64К. Это
ограничение
было у PalmOS
включая
версию 4 и у
Хотсинка до
версии 5
включительно.
Условное
ограничение
сегмента GCC в 32К
лечится
заменой
скрипта для
линкера на text_64k.
*
Ограничение
смещения у
команды
вызова
процедуры в
32К. То есть,
если сегмент
больше 32К, то
функция из
начала не
может
вызвать
функцию в
конце
сегмента. Это
можно обойти
путем
перемещения
вызываемых
функций
"поближе" к
вызываемым
или
созданием
функций-заглушек
в середине
сегмента.
*
Ограничение
размера
глобальных
данных
программы.
Общий объем
глобальных
данных (в
сумме
инициализированных
и
неинициализированных)
должен
укладываться
в 64К. Замечу,
что
константные
инициализированные
данные
помещаются в
сегмент кода.
Что
усложнится
при попытке
добавить
новый
сегмент?
Самая
большая
проблема -
межсегментный
вызов
процедуры. В
случае
одного
сегмента
расстояние
между
процедурами
постоянно и
код вызова не
меняется
после
компиляции. В
случае
межсегментного
вызова
ресурсы
могут
располагаться
в
произвольных
участках
памяти и
смещение
нужно
корректировать.
Замечу, что в
односегментном
приложении
также
происходит
коррекция
области
данных. В
нижележащем
примере
значение
переменной pfn
будет
скорректировано.
Это возможно,
поскольку
сегмент
данных
находится в
динамической
памяти.
Копировать
же все
сегменты в
динамическую
память для
коррекции
неразумно и
расточительно.
<code>
void foo(void){
}
void *pfn = foo;
</code>
Все (оба ;-) )
производители
компиляторов
для PalmOS
предлагают
свои
поддержки
мультисегментности.
Gcc предлагает
следующий
способ:
* Всем
функциям
приписывается
атрибут с
именем
сегмента.
Функции
помещаются в
соответствующие
сегменты
единственного
получаемого
ELF-файла.
* В области
глобальных
переменных
хранятся
адреса всех
сегментов
* При вызове
функции из
другого
семента
происходит
сложение
смещения
функции от
начала
сегмента к
адресу
сегмента из
глобальной
памяти
В чем
ограничения
такого
метода:
*
Использование
глобальных
данных. Это
обозначает,
что при
вызове
программы
без
глобальных
переменных,
вызов
функций из
других
сегментов
попросту
невозможен.
При попытке
вызвать
произойдет
обращение к
несуществующей
области
глобалных
данных и Fatal Alert
неизбежен.
* Этот способ
никак не
расширяет
область
глобальных
данных.
* Проблемы с
доступом к
константным
данным.
Константные
данные могут
оказаться в
другом
сегменте и
тебовать
наличия
глобальных
данных.
* Неявные
функции и
методы
класса. C++
богат на
неявную
генерацию
неявного
кода. Следует
контролировать
куда будет
помещен код
темплейтов и
не
инлайновых
инлайнов.
Подробное
описание
мультисегментной
архитектуры
GCC здесь:
http://prc-tools.sourceforge.net/doc/prc-tools_3.html
Существует
альтернативный
способ
создания
мультисегментных
приложений с
помощью
утилиты multilink.
Смотри
описание
здесь: http://www.djw.org/product/palm/multilink/
Multilink
использует
другую идею:
* Исходные
файлы
компилируются
как обычно. Не
нужно
указывать
сегменты в
исходном
коде
* Утилита
получает на
вход
объектные
файлы и
необязательный
список
разбиения
функций по
сегментам.
* Утилита
разбивает
все функции
по сегментам
по списку и
добивает
оставшиеся
до
указанного
размера
сегментов.
* Если
функция foo из
сегмента segA
вызывает bar из
сегмента srgB, то
в segA
добавляется
заглушка для
bar, вызывающая bar.
* Для
вычисления
адреса bar
используются
данные,
которые
хранятся в feature memory.
Тем самым
наличие
глобальных
данных
необязательно.
* Полученные
сегменты
добавляются
в программу.
У этого
решения есть
один большой
минус -
невозможен
доступ к
константным
данным из
другого
сегмента.