OpenWiki

Palm Multi Segment

Palm Notes | Recent Changes | Title Index | User Preferences | Random Page | Help
Difference from prior major revision.
minor diff author 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
  
Такой способ 
позволяет 
запускать 
программы 
практически 
"на месте", 
выделяя 
только 
память под 
стек и 
глобальные 
переменные.
  
Какие 
ограничения 
накладываются на простое односегментное приложение? 
  * Размер 
ресурса 'code' #0 
ограничен 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. Тем самым наличие глобальных данных необязательно.
  * Полученные 
сегменты 
добавляются 
в программу.
  
У этого 
решения есть 
один большой 
минус - 
невозможен 
доступ к 
константным 
данным из 
другого 
сегмента.
  
  
  

Palm Notes | Recent Changes | Title Index | User Preferences | Random Page | Help
Edit this page | View other revisions
Print this page | View XML
Find page by browsing, searching or an index
Edited December 2, 2003 (hide diff)