Шаг 1.
Трансляция программ. Директива INCLUDE

    На этом шаге мы рассмотрим структуру ассемблерной программы и способы ее трансляции.

    Материал, приведенный в шагах этого раздела, базируется на книге В.Пирогова "Ассемблер для Windows". - СПб.:БХВ-Петербург, 2003. - 656 с.

    В изложении материала мы будем придерживаться использования пакета MASM версии 7 и TASM (TASM32.EXE версии 5.0, TLINK32.EXE версии 1.6.71). Рекомендуем пользоваться версиями не ниже указанных.

    При объяснении материала мы не будем останавливаться на тех командах, которые описаны в разделе 16-битное программирование, в необходимых случаях мы будем давать соответствующую ссылку.

    Двум стадиям трансляции (смотри шаг 26 в разделе 16-битное программирование) соответствуют две основные программы:

    Пусть файл с текстом программы на языке ассемблера называется PROG.ASM, тогда, не вдаваясь в подробный анализ, две стадии трансляции будут выглядеть следующим образом:

    c:\masm32\bin\ml /с /coff PROG.ASM
В результате появляется модуль PROG.OBJ, который затем линкуется следующей командой:
    c:\masm32\bin\Link /SUBSYSTEM:WINDOWS PROG.OBJ

    В результате появляется исполняемый модуль PROG.EXE. Конструкции и /coff являются параметрами программы ML.EXE, a /SUBSYSTEM:WINDOWS является параметром для программы LINK.EXE. О других ключах этих программ более подробно смотри приложение 1.

    Формат конечного модуля зависит от операционной системы. Установив стандарт на структуру объектного модуля, мы получаем возможность:

    Для иллюстрации процесса трансляции рассмотрим несколько простых, "ничего не делающих" программ.


    Пример 1.
.386P
;Плоская модель памяти.
.MODEL FLAT,  STDCALL

;Сегмент данных.
_DATA  SEGMENT   DWORD   PUBLIC  USE32   'DATA' 
_DATA  ENDS 
;Сегмент  кода.
_TEXT  SEGMENT  DWORD  PUBLIC USE32   'CODE'
START:
RET   ;Выход.
_TEXT  ENDS 
       END START
Текст этой программы можно взять здесь.

    В примере 1 представлена "ничего не делающая" программа. Назовем ее PROG1.


    Замечание. Команды микропроцессора и директивы макроассемблера будем писать заглавными буквами.
Итак, чтобы получить загружаемый модуль, выполним следующие команды:
    ML /с  /coff  PROG1.ASM
    LINK  /SUBSYSTEM:WINDOWS PROG1.OBJ

или для Турбо Ассемблера:

    TASM32  /ml  PROG1.ASM 
    TLINK32  -aa  PROG1.OBJ

    Примем пока параметры трансляции программ как некую данность и продолжим наши изыскания.

    Часто удобно разбить текст программы на несколько частей и объединять эти части еще на 1-й стадии трансляции. Это достигается посредством директивы INCLUDE. Например, один файл будет содержать код программы, а константы, данные (определение переменных) и прототипы внешних процедур помещаются в отдельные файлы. Часто такие файлы записывают с расширением INC.

    Именно такая разбивка демонстрируется в следующей программе.


    Пример 2. Иллюстрация использования директивы INCLUDE
;файл CONS.INC
CONS1 EQU 1000 
CONS2 EQU 2000 
CONS3 EQU 3000 
CONS4 EQU 4000 
CONS5 EQU 5000 
CONS6 EQU 6000 
CONS7 EQU 7000 
CONS8 EQU 8000 
CONS9 EQU 9000 
CONS10 EQU 10000 
CONS11 EQU 11000
CONS12 EQU 12000

;файл DAT.INC
DAT1 DWORD 0
DAT2 DWORD 0
DAT3 DWORD 0
DAT4 DWORD 0
DAT5 DWORD 0
DAT6 DWORD 0
DAT7 DWORD 0
DAT8 DWORD 0
DAT9 DWORD 0
DAT10 DWORD 0
DAT11 DWORD 0
DAT12 DWORD 0

;файл PROG2.ASM
.386P
;Плоская модель памяти.
.MODEL FLAT, STDCALL
;Подключить файл констант.
INCLUDE CONS.INC
;Сегмент данных.
_DATA SEGMENT DWORD PUBLIC USE32 'DATA'
;Подключить файл данных.
INCLUDE DAT.INC
_DATA ENDS
;Сегмент кода.
_TEXT SEGMENT DWORD PUBLIC USE32 'CODE'
START:
   MOV EAX,CONS1
   SHL EAX,1  ;Умножение на 2.
   MOV DAT1,EAX 
   MOV EAX,CONS2
   SHL EAX,2  ;Умножение на 4.
   MOV DAT2,EAX
   MOV EAX,CONS3
   ADD EAX,1000 ;Прибавим 1000. 
   MOV DAT3,EAX
   MOV EAX,CONS4
   ADD EAX,2000 ;Прибавим 2000.
   MOV DAT4,EAX
   MOV EAX,CONS5
   SUB EAX,3000 ;Вычесть 3000.
   MOV DAT5,EAX
   MOV EAX,CONS6
   SUB EAX,4000 ;Вычесть 4000.
   MOV DAT6,EAX
   MOV EAX,CONS7
   MOV EDX,3
   IMUL EDX ;Умножение на З.
   MOV DAT7,EAX
   MOV EAX,CONS8
   MOV EDX,7 ;Умножение на 7.
   IMUL EDX
   MOV DAT8,EAX
   MOV EAX,CONS9
   MOV EBX,3 ;Деление на З.
   MOV EDX,0
   IDIV EBX
   MOV DAT9,EAX
   MOV EAX,CONS10 
   MOV EBX,7 ;Деление на 7.
   MOV EDX,0 
   IDIV EBX
   MOV DAT10,EAX
   MOV EAX,CONS11
   SHR EAX,1 ;Деление на 2.
   MOV DAT11,EAX
   MOV EAX,CONS12
   SHR EAX,2 ;Деление на 4.
   MOV DAT12,EAX
   RET       ;Выход.
_TEXT ENDS 
   END START
Эти файлы можно взять здесь.

    Программа примера 2 также достаточно бессмысленна, но зато демонстрирует удобства использования директивы INCLUDE. Напомним, что мы не останавливаемся в книге на очевидных командах микропроцессора. Заметим только по поводу команды IDIV. В данном случае команда IDIV осуществляет операцию деления над операндом, находящемся в паре регистров EDX:EAX. Обнуляя EDX, мы указываем, что операнд целиком находится в регистре EAX.

    Трансляция программы осуществляется так, как это было указано ранее для ассемблеров MASM и TASM в примере 1.


    Замечание о типах данных. При изложении материала вы встретитесь в основном с тремя типами данных (простых):

    При этом используются следующие стандартные обозначения:


    На следующем шаге мы рассмотрим применение объектных модулей.




Содержание Следующий шаг