Материал: TextmetukSPO

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Использования этого файла сценариев для получения исполняемого файла exmpl.exe из исходного файла exmpl.s достигается вызовом в командной строке

asm2exe exmpl

Заметим, что оба рассмотренных файла fasm и asm2exe сценариев должны быть заданы с атрибутами исполнения, что можно достигнут выполнив команды

chmod +x fasm chmod +x asm2exe

Ассемблер AT&T использует сокращенные директивы описания сегментов. Они подобны директивам сокращенного описания сегментов в макроассемблерах MASM, TASM и т.п. Задаются эти директивы служебными словами .data , .text. Стек явно, также как и для ОС MS Windows NT, не описывается. Точка входа в программу (метка начала ее выполнения при запуске) имеет стандартное наименования, отклонятся от которого не дозволяется. Это наименование совпадает с аналогичным наименованием точки входа в ассемблере NASM и задается как _start. Но здесь оно обязательно задается с помощью завершающего двоеточия. Таким образом метка запуска программы на ассемблере на выполнение имеет вид

_start:

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

_start:

.global _start

Заметим, что директиву .global можно помещать в любом месте исходного модуля. Директива END в рассматриваемом ассемблере не используется.

Перед обозначением регистра обязательно должен стоять служебный символ %, так что регистр EAX обозначится здесь как %eax и т.п.

Все непосредственные операнды (константы в качестве операндов) должны обязательно предваряться служебным символом $. Сами числовые константы задаются в том же виде, как и в языке Си. Так что вызов прерывания с десятичным номером 128 должно задаваться командой

int $0x80

Вкомандах, способных выполнять действия с данными различного размера, конкретный размер обрабатываемых данных обязательно задается последним (и дополнительным относительно синтаксиса Intel) символом, в качестве которого допускаются буквы b, w и l. Они обозначают, соответственно, размер в байт, слово (16 битов) и длинное слово (32 бита).

Вмногооперандных командах операнд-получатель данных размещается самым правым (а не самым левым как в ассемблере Intel, MASM и TASM). Таким образом занесение константы 12 в регистр EDX с помощью команды пересылки должно записываться как

movl $12, %edx

Метки задаются обычным образом в виде произвольного буквенного наименования и дополнительного символа двоеточия. Внешние символы указываются директивой .global или global. Она служит как для задания общедоступных символов

56

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

Для задания текстовых строк предназначены два основных вида директив: .ascii и .asciz. Вторая из них автоматически добавляется при трансляции в конец заданного в ней текста служебный символ окончания текста ('\0' равносильный нулевому содержимому байта). Таким образом, задание обозначаемого именем msg текста Привет мир! можно задать директивой

msg: .ascii "Привет мир!"

Если же нудно задать этот текст для обработки по завершающему нулевому байту, то целесообразно описать его данные в виде

msg: .asciz "Привет мир!" или в виде

msg: .ascii "Привет мир!\0"

Альтернативой директиве .ascii служит директива .string, которая имеет ту же форму операндов.

Последовательность байтов задается директивой .byte, 16-тиразрядных слов - директивой .word, последовательность из 32-битных слов дается директивой .int или .long. В качестве операндов этих директив может использоваться одно или более числового значения, разделенные запятыми. Кроме того, могут использоваться обозначения кодов отдельных символов, помещенные в апострофы. Например,

xyz: .byte 'A',10,13,'$'

Заполнение последовательности байтов нулями задается директивой

.space число

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

.zero число_байтов

Для задания эквивалентностей (именований выражений) предназначена директива

.equ символ, выражение

которая присваивает имени символ значение выражения, заданного в ней. Рассмотрим простейшие примеры использования данного ассемблера, опира-

ясь на соглашение о доступе к базовым функциям Linux, изложенное в первой главе. Для ввода текста в буфер данных, обозначенный меткой buffer, в этом ассемблере следует использовать последовательность команд

movl $3, %eax movl $0, %ebx movl $buffer, %ecx movl $число, %edx int $0x80

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

57

довательности в регистре EAX оказывается число действительно введенных символов.

Для вывода текста, заданного с завершающим нулем в массиве, обозначенным меткой txt, следует в данном ассемблере использовать последовательность команд

movl $4, %eax movl $1, %ebx movl $txt, %ecx movl $число, %edx int $0x80

где вместо параметра число нужно записать соответствующее числовое значение, равное числу выводимых байтов.

Для завершения программы на данном ассемблере нужно использовать последовательность

movl $1, %eax int $0x80

которая задает выполнение функции exit(0) для нормального завершения программы.

Следующий пример более подробно демонстрирует описанные средства и возможности ассемблера AT&T.

.data

buffer: .zero 80

.global _start _start:

movl $3, %eax movl $0, %ebx movl $buffer, %ecx movl $80, %edx int $0x80

movl %eax, %edx lea buffer,%ebx movb $'!',1(%ebx)

movb $10,1(%ebx,%edx)

movl $4, %eax movl $1, %ebx movl $buffer, %ecx int $0x80

movl $1, %eax int $0x80

Этот пример задает ввод не более 80-ти символов произвольного текста, число которых заноситься в регистр edx. Затем на место второго символа введенного текста (со смещением +1 от начала текста в буфере buffer) заносится символ

58

восклицательного знака, а после всех введенных символов дополнительно приписывается управляющий символ перевода строки (символ \n с числовым значением 10). Этот управляющий символ пишется в буфер со смещением от его начала, равным сумме содержимого регистра EDX и дополнительного смещения 1.

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

смещение(базовый_регистр, индексный_регистр)

Нулевое смещение может опускаться. При отсутствии базового регистра - если используется только индексный регистр, но не базовый, требуется запись в виде

смещение(, индексный_регистр)

причем запятая в этой записи обязательна. Если же используется только базовый регистр, но не используется индексный, допустимой является запись в виде

смещение(базовый_регистр)

Например Intel-ассемблерная запись [ebx+10] должна записываться здесь в виде 10(%ebx), запись [esi] в виде 0(, %esi) или (, %esi). Впрочем, в 32-битной архитектуре регистры ESI и EDI можно использовать и как базовые, а поэтому последний операнд записывать и в виде (%esi).

ПРИЛОЖЕНИЕ 2.

Дополнительные сведенья по ассемблеру NASM

Для создания файла листинга, где сообщения об ошибках присутствуют сразу после строки программы, содержащей ошибки, предназначен опцию –l (строчная латинская буква L). Примером такого использования является

nasm -f elf file.asm -l file.lst

Для перенаправления сообщений об ошибках в файл следует применять опцию –E.

Примером переназначения ошибок в файл является строка вызова nasm -f elf file.asm -E file.err

Для переназначения сообщений об ошибках в стандартный вывод можно предназначена опция –s.

Ее примером использования может служит следующая строка вызова nasm -s -f elf file.asm

При большом числе ошибок целесообразно использовать командный конвейер и специальную команду разбиения на страницы вывода, называемую в рассматриваемых операционных системах more. Само такое использование дается примером

nasm -s -f elf file.asm | more

59

Ассемблер NASM дает специальную трактовку символов, начинающихся с точки. Метка, начинающаяся с точки, обрабатывается как локальная. Это означает, что она неразрывно связана с предыдущей нелокальной меткой. Например:

label1

; некоторый код

.loop

; еще какой-то код

jne .loop

ret

 

label2

; некоторый код

.loop

; еще какой-то код

jne .loop ret

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

Данный способ позволяет обращаться к локальным меткам из другой части кода. Это достигается путем описания локальной метки на основе предыдущей нелокальной. Описания .loop в примере выше в действительности описывают два разных символа: label1.loop и label2.loop, поэтому если вам надо, то можете написать:

label3 ; некоторый код ; и т.д.

jmp label1.loop

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

Выше рассматривались правила построения исходных текстов на ассемблере для экспортируемых функций из разделяемых объектов. Для экспорта данных требуется использовать служебное слово data вместо служебного слова function.

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

global array:data array.end-array ; где далее указать размер массива array: resd 128

.end:

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

60

Источник: https://studfile.net/preview/16469866/