Как собрать программу на ассемблере

В предыдущей части нашего урока мы познакомились с процессором Cortex-M3, регистрами ядра, создадим и настроим проект, также познакомимся с несколькими необходимыми директивами.

Давайте теперь в нашу процедуру Start добавим хотя бы одну строку с кодом

Assembly (x86)
Start PROC
MOV R 0 , # 0

Inline Assembler Overview

The inline assembler lets you embed assembly-language instructions in your C and C++ source programs without extra assembly and link steps. The inline assembler is built into the compiler — you don’t need a separate assembler such as the Microsoft Macro Assembler (MASM).

Because the inline assembler doesn’t require separate assembly and link steps, it is more convenient than a separate assembler. Inline assembly code can use any C or C++ variable or function name that is in scope, so it is easy to integrate it with your program’s C and C++ code. And because the assembly code can be mixed with C and C++ statements, it can do tasks that are cumbersome or impossible in C or C++ alone.

Hello World на Ассемблере (x86)

The __asm keyword invokes the inline assembler and can appear wherever a C or C++ statement is legal. It cannot appear by itself. It must be followed by an assembly instruction, a group of instructions enclosed in braces, or, at the very least, an empty pair of braces. The term » __asm block» here refers to any instruction or group of instructions, whether or not in braces.

The following code is a simple __asm block enclosed in braces. (The code is a custom function prolog sequence.)

// asm_overview.cpp // processor: x86 void __declspec(naked) main() < // Naked functions must provide their own prolog. __asm < push ebp mov ebp, esp sub esp, __LOCAL_SIZE >// . and epilog __asm < pop ebp ret >>

Читайте также:
Что входит в программу аниматора

Alternatively, you can put __asm in front of each assembly instruction:

__asm push ebp __asm mov ebp, esp __asm sub esp, __LOCAL_SIZE

Since the __asm keyword is a statement separator, you can also put assembly instructions on the same line:

__asm push ebp __asm mov ebp, esp __asm sub esp, __LOCAL_SIZE

END Microsoft Specific

Источник: learn.microsoft.com

ASSEMBLERтип процессора
.model flat, stdcall ; модель памяти и вызова подпрограмм
;объявление включаемых (заголовочных) файлов, макросов, макроопределений,
; также внешних определений
.data
; Инициализированные данные
.data?
; неинициализированные данные
.const
; константы
.code
; исполняемый код
End

Процессоры могут быть 386, 486, 586, обычно всегда стоит 386p, но ничто вам не мешает поставить 486p или 586. Модель памяти всегда flat и никакой другой не может быть. Вызов подпрограмм обычно всегда stdcall, стандарт вызова почти всех API функций. Секция .data секция с инициализированными данными она включается в исполняемый файл.

ЯЗЫК АССЕМБЛЕРА за 3 МИНУТЫ

Секция .data? секция с неинициализированными данными, она не включается в исполняемый файл и появляется только тогда, когда программа загружается в память. Секция .const секция констант. Секция .code содержит исполняемый код программы. В конце программы всегда должно стоять слово end, которая задаёт точку входа программы, т.е. место с которого начнётся выполняться программа.

Секции .data, .data? имеют полный доступ. Разумеется, секции .const и .code имеют атрибут доступа — только чтение. Секция .const наиболее редко встречается в программах, так как константы можно задавать с помощью макроопределений.
При программировании под Win32 мы не имеем доступ к портам ввода вывода и не можем вызывать прерывания (самые главные команды в DOS), у нас есть только WIN API, которые экспортируют системные библиотеки. Вызывая API функцию, вы просто передаёте управление точке входа функции (точка входа функции это первая инструкция функции), сама функция находится где-то в памяти вашего процесса внутри некоторой библиотеки. API функции находятся в библиотеках kernel32.dll, user32.dll, gdi32.dll (классика) advapi32.dll и т.д., для того чтобы использовать некоторую функцию этих библиотек надо сначала загрузить нужную библиотеку в свою память, либо включить используемые функции в таблицу импорта и тогда загрузчик загрузит библиотеки за вас. О kernel32.dll можно не волноваться, потому что эта библиотека есть в каждом процессе в любом случае, тем более она там существует ещё до запуска главной нити процесса, она даже проецируется в вашу память всегда по одинаковым адресам. Как я уже говорил все функции, используют модель вызова stdcall, а значит, параметры подпрограмме передаются «задом-на-перёд» и вызываемый очищает стек. Общий вид вызова API функции будет такой:

Push параметр 3
Push параметр 2
Push параметр 1
Call функция ; если быть точнее то здесь должен стоятб ажрес функции
; т.е. адрес её точки входа

Каждая программа в Win32 в конце своего выполнения ОБЯЗАТЕЛЬНО должна вызвать функцию ExitProcess. Сами подумайте, после выполнения последней инструкции программы, дальше идёт пустота, даже если там что-то осмысленное, все равно у выделенной памяти есть конец, а после конца идёт невыделенная (т.е. несуществующая) память. Процессор начнёт выполнять непоймёшь чё, пойдут глюки, и ваша программа даст в конце хорошо всем знакомый звук — «ДУНГ». А это уже бессмыслица. Вот определение ExitProcess из MS SDK:

VOID ExitProcess(
UINT uExitCode // exit code for all threads
);
uExitCode — это значение никогда не используется и всегда равно 0.

Первая программа.
Теперь я приведу вам программу, которая выводит легендарное сообщение «Hello, World!».

extrn ExitProcess:PROC
extrn MessageBoxA:PROC

Ttl db «First ASSEMBLER program»,0h
Msg db ‘Hello, World. ’,0h

start:
push 0h
push offset Msg
push offset Ttl
push 0h
call MessageBoxA
push 0h
call ExitProcess
end start

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru