Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
flor_apparato-orientirovnnoe_prog.doc
Скачиваний:
89
Добавлен:
15.06.2014
Размер:
926.72 Кб
Скачать

5.5. Особенности использования объектных файлов формата coff

Кроме формата OBJ для объектных модулей, предназначенных для Windows, используется формат, введенный позже фирмой Microsoft и называемый COFF (Common Object File Format). В обозначениях NASM он задается служебным сокращением win32. Для получения из такого формата исполняемых файлов следует применять компоновщик Microsoft или совместимые с ним.

Особенностью последнего варианта являются специфические имена системных функций API, хотя и подобные системным именам прототипов из документации для языка Си, но все же заметно отличные от них. Это отличие заключается в том, что исходное имя от прототипа на Си дополняется символом '@', за которым записывается число байтов в области аргументов вызова этой функции (это число можно посчитать исходя из информации прототипа и заголовочных файлов или использовать дополнительную информацию из заголовочных файлов специально для ассемблерных программ). Кроме того, перед исходным именем из прототипа приписывается дополнительный символ '_' (символ подчеркивания).

Такие усложнения обусловлены техническим решением, принятым Microsoft для библиотек импорта формата COFF, но не являются собственно ограничением самого формата. Тем не менее, при использовании компоновщиков от Microsoft или близко совместимых с ними, оказывается необходимым применять объектные файлы, имена системных функций в которых должны точно соответствовать описанным требованиям.

Обозначение сегментов в исходной программе для данного рассматриваемого формата достаточно задавать в простейшей форме с одним стандартным именем (так как вся эта система ориентирована только на 32-битную архитектуру операционной системы). В качестве метки входа в программу следует использовать имя _start, которое нужно объявить глобальным с помощью директивы GLOBAL.

В листинге 5.5.1 приведена программа на NASM ассемблере для результирующего формата win32 объектных файлов. Причем для разнообразия в ней решается задача ввода строки текста, изменение в ней второго из введенных на символ ‘!’ и вывод полученной строки.

GLOBAL _start

EXTERN _GetStdHandle@4, _WriteFile@20, _ExitProcess@4

EXTERN _ReadFile@20

segment .text

_start:

push dword STD_OUTPUT_HANDLE

call _GetStdHandle@4

mov [hstdout],eax

push dword STD_INPUT_HANDLE

call _GetStdHandle@4

mov [hstdin],eax

;--- ReadFile(hstdin, buf, 80, &actlen, NULL)

push dword 0

push dword actlen

push dword 80 ; number of bytes

push dword buf ; address of txt

push dword [hstdin] ; N handle=hstdout

call _ReadFile@20

mov byte [buf+1],'!'

;--- WriteFile(hstdout, buf, actlen, &actlen, NULL)

push dword 0

push dword actlen ; address of actual byte number

push dword [actlen] ; number of bytes (value !)

push dword buf ; address of txt

push dword [hstdout]; N handle=hstdout

call _WriteFile@20

; ExitProcess(0)

push dword 0

call _ExitProcess@4

segment .data

buf times 80 db 0

hstdin dd 0

hstdout dd 0

actlen dd 0

STD_INPUT_HANDLE equ -10

STD_OUTPUT_HANDLE equ -11

Листинг 5.5.1. Программа для формата win32 объектного файла Windows

Для превращения программы NASM в объектный файл формата win32 и изготовления из последнего исполняемой программы можно воспользоваться командным файлом с текстом, приведенным в листинге 5.5.2

nasmw -f win32 %1.asm -l %1.lst

link /ENTRY:start /SUBSYSTEM:CONSOLE %1.obj kernel32.lib

Листинг 5.5.2. Командный файл для получения программы Windows

через формат win32 c использованием link.exe

Использование предложенного варианта требует наличия доступных компоновщика фирмы MS с именем LINK.EXE и библиотеки импорта KERNEL32.LIB, предназначенной для него, а также библиотеки MSPDB60.DLL (так называемой библиотеки динамической компоновки или, иначе, библиотеки совместно используемых при выполнении объектов).

Заметим, что свободно распространяемый компоновщик alink.exe, о котором рассказывалось выше, не позволяет использовать библиотеки импорта в формате COFF (в частности библиотеку KERNEL32.LIB), хотя сам этот формат для объектных файлов и библиотек объектных файлов данный компоновщик поддерживает. При использовании этого компоновщика приходится применять ту же библиотеку импорта win32.lib, которая обсуждалась выше, и организовывать доступ к системным функциям через эту библиотеку, т.е. в соглашениях, отличных от COFF. При этом в исходных текстах программ ассемблера придется использовать обозначения системных функций без характерных для библиотек импорта COFF префиксов и суффиксов (что программисту может показаться не только не худшим, а предпочтительным вариантом). К сожалению, такой компромиссный подход делает невозможным использовать объектные файлы формата COFF, созданные транслятором из MS Visual C или подобным ему. Следует учитывать, что достаточно характерным использованием ассемблера оказываются разработки, в которых часть объектных файлов формируется на языке высокого уровня, а только часть - пишется собственно на ассемблере. Эта причина заставляет разбираться с особенностями программирования для различных видов объектных файлов и соблюдать в таких разработках общие форматы построения объектных файлов.

С учетом широкого распространения формата COFF, рассмотрим два вспомогательных приема, позволяющих использовать стандартную форму обращения к системным функциям ОС MS Windows. Оба они являются вариациями автоматизированного формирования имен системных функций с префиксами и суффиксами от MS. Это формирование выполняется на основе обычного имени системной функции, взятого из документации по программному интерфейсу программ (API).

Первый из приемов заключается в использовании специальных файлов, имеющих обычно расширение INC и содержащих фактически переименование от простого наименования к полному. Например, для доступа к системной функции GetStdHandle, имеющей полное имя _GetStdHandle@4 в COFF, используется директива ассемблера

#define GetStdHandle EQU _GetStdHandle@4

совместно с директивой

extern _GetStdHandle@4

Применение таких файлов, содержимое которых включается, в свою очередь, в исходный текст разрабатываемой программы директивой

#include имя специального файла вспомогательных описаний

позволяет в тексте ассемблерных программ по-прежнему писать простое имя системной функции, но это имя будет заменяться для объектного файла требуемой формой полного имени [5].

Второй подход, используемый в примерах инструментального пакета NASMW, основан на применении специализированной макрокоманды с именем sc, содержащейся во вспомогательном файле windows.inc (также содержащегося в этом пакете). Указанная макрокоманда (вместе с другими, обеспечивающими ее функционирование) используется в тексте ассемблерной программы, чтобы в конкретном месте сформировать обращение по полному имени. Более того, она содержит внутренние средства, позволяющие аргументы вызова писать прямо в качестве аргументов этой макрокоманды (вместо того, чтобы непосредственно записывать все команды укладки аргументов в стек перед вызовом системной функции). Например, вызов функции GetStdHandle для получения хэндла стандартного вывода записывается в виде

sc GetStdHandle, STD_OUTPUT_HANDLE

Применение этих средств особенно удобно для вызова системных функций, имеющих много аргументов. В данном изложении мы не будет далее останавливаться на этой достаточно эффективной возможности, отсылая читателя к внутренней информации указанного программного пакета и примеров программирования, содержащихся в нем.

Вместо компоновщика LINK.EXE от Microsoft для компоновки объектных модулей формата COFF совместно с библиотеками импорта этого же формата может быть использован компоновщик фирмы Sybase с именем wlink.exe, входивший в состав системы программирования Watcom C++. Указанная система программирования широко функциональная, что проявляется в возможности строить с ее помощью исполняемые файлы для большого числа операционных систем. Побочным следствие такой широты возможностей стало обилие аргументов вызова программы компоновщика, которые могут быть заданы при компоновке. В данном контексте мы рассмотрим вариант построения исполняемого файла только для современных версий операционных систем типа Windows.

В рассмотренном выше примере - для компоновки объектного файла - в составе командного файла достаточно воспользоваться вызовом вида

wlink File %1.obj FORMat window nt RUntime console OPtion START=_start Library kernel32.lib

В этом вызове использованы аргументы, которые задают: обрабатываемый объектный файл, формат выходного исполняемого файла, среду выполнения, режим с единственной опцией - меткой запуска кода программы и библиотеку. Все эти аргументы имеют ключевую форму, которая позволяет использовать их в произвольном порядке внутри строки вызова, но требует задания специальных ключевых слов, именующих каждый аргумент. В общем случае ключевое слово FILE определяет следующий за ним перечень как имена объектных файлов, подлежащих компоновке. Сам перечень задается перечислением имен через разделительные запятые, если файлов в этом списке более одного. Допускается сокращенная форма обозначения ключевого слова, которая в данном случае сводится к единственному символу F.

Для задания исполняемых файлов формата Portable Executable (PE) синтаксис компоновщика WLINK требует указания ключевого слова FORMAT, которое может быть сокращено до его начальной части FORM, и условного обозначения 32-битных систем MS Windows, которое в данном компоновщике задается как windows nt. (Обозначение единственным словом windows было предназначено для 16-битной предшественницы современных MS Windows.)

С помощью аргумента RUNTIME выбирается, будет ли программа выполнятся в среде графической оболочки или в консольном режиме. Во втором случае используется значение CONSOLE, а в первом (которое данное изложение не применяет) - значение WINDOWS. Аргумент, задающий опции, указывается ключевым словом OPTION, позволяющим сокращать его до двух первых букв. В качестве значения этого аргумента используется, в свою очередь единственный необходимый для текущих целей режим. Он указывает глобальную метку исходного файла, обозначающую начальную точку при запуске исполняемого файла, получаемого при компоновке. Задание режима записывается в форме

START=имя_точки_входа

Последним использованным аргументом задаются библиотеки, служащие, как правило, для импорта имен системных функций. В общем случае библиотеки задаются списком в виде перечисления через запятые, в нашем частном случае используется единственная библиотека kernel32.lib. Ключевое слово задания аргумента списка библиотек записывается как Library и может быть сокращено до единственного первого символа этого ключевого слова.

С учетом этог, рассматриваемая командная строка может быть сокращена до

wlink File %1.obj FORM window nt RU console OP START=_start L kernel32.lib

хотя в этом случае она труднее воспринимается программистом, если последний лишь эпизодически использует что-то подобное. Другим вариантом сокращения записи вызова компоновщика является использования косвенного вызова. В этом случае все аргументы, используемые достаточно часто, записываются в отдельный файл, например с именем файларг, а в самом вызове компоновщика использование содержимого этого файла указывается в виде @файварг.

Например, для наших текущих целей может быть построен вспомогательный файл с именем aline.lin, помещенный в каталоге C:\UTIL и содержащий строки

FORMat window nt

RUntime console

OPtion

START=_start

Library kernel32.lib

а вызов компоновщика быть записан в самом командном файле как

wlink F %1.obj @C:\UTIL\aline.lin

Наконец, целиком командный файл, позволяющий выполнять компиляцию исходной программы с языка NASM и ее компиляцию утилитой WLINK, может быть записан в виде

nasmw -f win32 %1.asm -l %1.lst

wlink F %1.obj @C:\UTIL\aline.lin

Листинг 5.5.3. Командный файл для получения программы Windows

через формат win32 с использованием wlink.exe

Последний вариант обеспечивает как компактность, так и содержательную развернутость информации о деталях построения исполняемого файла.

Соседние файлы в предмете Системное программное обеспечение