Программирование на ассемблере под PocketPC

Дата публикации 7 июл 2004

Программирование на ассемблере под PocketPC — Архив WASM.RU

Для начала разберемся с основными понятиями и определениями: PocketPC и WindowsCE – это (с недавних пор) одна и та же операционная система реального времени (real-timeOS); предназначена она для т.н. встраиваемых (embedded) систем (КПК, банкоматы, бортовые компьютеры в автомобилях и т.п.).

Одной из главных характеристик систем реального времени является стабильность. Не беспокойтесь – Microsoft не отступила от своих традиций: WinCE подвисает довольно часто, причем даже от вполне безобидных ошибок в прикладных программах. Поэтому прежде чем запускать программу в КПК ее нужно тщательно обследовать на эмуляторе.

Еще одно преймущество WindowsCE– компактность. В ней реализовано в десять раз меньше API-функций, чем, к примеру, в WinNT. Для сравнения – главная системная библиотека в WindowsXP (kernel32.dll) весит 914 Кб, тогда как аналогичная библиотека из WindowsCE (coredll.dll) – всего 509 Кб. О чем говорят эти цифры? Да ни о чем J. Просто из coredll.dll выкинули много старых, ненужных для совместимости с Win9xфункций. Правда, добавили несколько новых. Вообще, некорректно сравнивать настольные ОС со встроенными, поэтому оставим эту тему.

Принцип модульности – вот основное преимущество этой, да и всех других встраиваемых ОС: WinCE состоит из множества модулей (около 220 «exe» и «dll» файлов, причем каждый модуль состоит из нескольких компонент («lib»), что делает эту ОС совсем пластилиновой), которые можно легко отключать и включать, т.е. WinCE – это конструктор, который может собрать любой под свои конкретные нужды с помощью PlatformBuilder-а, и если, к примеру, вашему холодильнику не нужны сокеты – вы просто не включаете их в конечный build. Что-то подобное можно наблюдать при инсталляции настольных версий Win – нам дают возможность избавиться от некоторых компонент, однако ядро и системные библиотеки остаются неизменными. Здесь же можно менять абсолютно все, вплоть до ядра. Таким образом, достигается минимальный размер и максимальное быстродействие. В принципе, по заверениям разработчиков, всю WinCE можно уместить в 400 Кб и она будет работать с 32 Кб оперативной памяти. С графическим интерфейсом (модуль GWES) она потянет уже на 4 Мб.

WinCE поддерживает множество процессоров (ARM, MIPS, x86), полный список можно посмотреть здесь:

http://www.microsoft.com/windowsce/Embedded/resources/processors.asp

Архитектура WinCE не является темой данной статьи, об этом вы можете почитать в MSDN. Поэтому перейдем непосредственно к главному.

Что необходимо для того, чтобы написать простейшую программку на асме для WinCE? Прежде всего – это … (нет, не больная психика, хотя не без этого) ассемблер для нужного проца, линкер и само устройство (или его эмулятор). Мой КПК Toshibae755 стоит на IntelPXA255 проце (который, в свою очередь, стоит на архитектуре ARM 5TE) . Поэтому в качестве ассемблера я использовал MSARMASM, который идет вместе с eVC (и который вы можете скачать по ссылке в конце статьи). Линкер – самый обычный MSlink.

Следует отметить, что ARMASM снабдили какой-то кой-как, на скору рученьку слепленной документацией (кое-что есть в MSDN, кое что есть в документации от eVC), хотя, очень возможно, что он и не содержит никаких неописанных возможностей.

В Интернете существует достаточное количество качественных ARM-ассемблеров, однако ни один из известных мне не знает ни про COFF, ни про PE (а именно он, кстати, и используется в WinCE).

Сразу признаюсь – на то чтобы простейшее «HelloWorld» приложение скомпилировалось и нормально запустилось я убил целый день. Однако результат оправдывает затраченные усилия – в итоге получился в три раза меньший по сравнению с С-шным exe-шник, а критерий размера ох как критичен для emb-систем, что бы там ни говорили настольные сотоварищи.

Предполагается, что вы более-менее знакомы с программированием под Win32 на ассемблере и с ARM-овским асмом.

Код стандартного «HelloWorld» выглядит следующим образом:

Код (Text):
  1.  
  2. ;---------------------cut here-------------------------------------------------------------------------
  3.         include     wince.inc
  4.    
  5.         IMPORT  MessageBoxW
  6.         IMPORT  ExitThread
  7.  
  8.         EXPORT  start
  9.  
  10.         AREA        .text, CODE
  11. start
  12.         eor     R0, R0, R0
  13.         adr     R1, mestext
  14.         adr     R2, mestit
  15.         mov     R3, #MB_OK
  16.         bl      MessageBoxW
  17.  
  18.         eor     R0, R0, R0
  19.         bl      ExitThread
  20.    
  21. mestext dcb "H",0,"e",0,"l",0,"l",0,"o",0," ",0,"w",0,"o",0,"r",0,"l",0,"d",0,0,0  
  22. mestit      dcb "A",0,"S",0,"M",0,0,0
  23.    
  24.         END
  25. ;---------------------cut here-------------------------------------------------------------------------

Пробежимся по каждой строчке кода.

Код (Text):
  1.  
  2. <strong>include wince.inc</strong>

wince.inc – быстро слепленный файлик, пока что кроме определений для MessageBoxW ничего не содержит. Надеюсь, когда-нибудь в него добавятся новые строки... Кстати, наблюдательный читатель сразу обратит внимание на то, что численно все определения для WinCE совпадают с «настольными», однако их значительно меньше…

Код (Text):
  1.  
  2. IMPORT  MessageBoxW
  3. IMPORT  ExitThread

armasm не поддерживает директиву типа includelib, поэтому каждую импортируемую функцию нужно указывать вот таким вот образом.

Код (Text):
  1. EXPORT  start

Дело в том, что без функции WinMainCRTStartup (которая автоматически создается в С) для платформы WindowsCE link.exe не сможет создать exe-файл - не найдя этой функции в объектнике, созданном armasm-ом, он просто грязно выругается. Поэтому мало того, что метку точки входа необходимо указать в экспорте, так еще и в параметрах к link.exe об этом нужно явно сказать при помощи опции /entry. Помнится, ml.exeсам делал всю подобную грязную работу и автоматически «назначал» точкой входа метку, которая была указана после директивы END. armasm настолько сырой (и, складывается впечатление – никому не нужный), что подобных наворотов просто не поддерживает.

Код (Text):
  1. AREA        .text, CODE

Здесь все понятно – это начало сегмента кода (.text – это имя, и может быть любым)

Код (Text):
  1.  
  2. eor     R0, R0, R0
  3. adr     R1, mestext
  4. adr     R2, mestit
  5. mov     R3, #MB_OK
  6. bl      MessageBoxW

В отличие от x86 (где параметры передаются в стеке) здесь параметры в функции передаются в регистрах (первый – в R0, второй – в R1 и т.д.). Результат возвращается в R0 (аналог EAX на x86). Здесь происходит вызов функции MessageBoxW – на экран выводится окошко с текстом. Почему W? Дело в том, что WinCE поддерживает только Unicode. MessageBoxA в coredll даже не пахнет. Хорошо это или плохо – программисту на асме вообщем-то как то все равно :smile3:, места больше в два раза жрет только…

Код (Text):
  1.  
  2. eor     R0, R0, R0
  3. bl      ExitThread

Почему ExitThread, а не ExitProcess? Все достаточно загадочно – дело в том, что coredll вообще не экспортирует ExitProcess, хотя в MSDN-е написано обратное. Близкий родственник – TerminateProcess есть, однако применять его крайне не рекомендуется. Еще больше смутила следующая строка, обнаруженная в одном из инклюдов к eVC:

#define ExitProcess(code) TerminateProcess (GetCurrentProcess (), (code))

Если у кого есть мысли по поводу того, зачем было избавляться от ExitProcess – прошу в комментарии. ExitThread из основного потока аналогичен ExitProcess, именно им я воспользовался (все таки, куда делся ExitProcess?)

С mestext и mestit все и так понятно – такая убогость возникла из-за того, что dcw для ASCII-символов в armasm-е не поддерживается, а писать макрос как-то не было времени.

Несколько слов по поводу компиляции:

armasm.exe -32 -cpu xscale entry.s

-32 – генерить 32-битный код.

xscale – мой проц

link.exe coredll.lib /nologo /entry:"start" /subsystem:windowsce /machine:arm "entry.obj"

/machine:arm – без этого параметра PocketPC ругается и кричит, что формат файла неправильный. На самом деле все что он делает – меняет байт Machine в заголовке PE с Thumbна ARM, хотя почему там оказался 16-битный ARM вместо 32-х битного? Это значит лишь то, что параметр -32 в armasm просто не работает… L

Помните, в начале статьи я упоминал о глюкавости WinCE? Можете сами поэкспериментировать. Задайте, например, выравнивание секций на 4 байта. В итоге вы получите еще в три раза меньший файл… (716 байт) и безумное поведение WinCE при попытке его запустить.

Все необходимые файлы (кроме link.exe) можно скачать тут.

Это все. В следующей статье по WinCE попытаемся рассмотреть более насущные проблемы – например, написание драйвера под эту замечательную ОС.

© Broken Sword

0 960
archive

archive
New Member

Регистрация:
27 фев 2017
Публикаций:
532