- •Системное программное обеспечение
- •Структура Windows NT
- •Структура Windows NT
- •Структура Windows NT
- •Структура Windows NT
- •Структура Windows NT
- •Структура Windows NT
- •Структура Windows NT
- •Структура Windows NT
- •Драйверы устройств в Windows NT
- •Драйверы устройств в Windows NT
- •Драйверы устройств в Windows NT
- •Драйверы устройств в Windows NT
- •Драйверы устройств в Windows NT
- •Драйверы устройств в Windows NT
- •Драйверы устройств в Windows NT
- •Драйверы устройств в Windows NT
- •Драйверы устройств в Windows NT
- •Драйверы устройств в Windows NT
- •Драйверы устройств в Windows NT
- •Драйверы устройств в Windows NT
- •Структура простейшего драйвера режима ядра в Windows NT
- •Структура простейшего драйвера режима ядра в Windows NT
- •Структура простейшего драйвера режима ядра в Windows NT
- •Структура простейшего драйвера режима ядра в Windows NT
- •Структура простейшего драйвера режима ядра в Windows NT
- •Структура простейшего драйвера режима ядра в Windows NT
- •Структура простейшего драйвера режима ядра в Windows NT
- •Структура простейшего драйвера режима ядра в Windows NT
- •Структура простейшего драйвера режима ядра в Windows NT
- •Структура простейшего драйвера режима ядра в Windows NT
- •Структура простейшего драйвера режима ядра в Windows NT
- •Лекция № 11 «Использование ассемблера с языками высокого уровня»
- •Использование ассемблера с языками высокого уровня
- •Использование ассемблера с языками высокого уровня
- •Использование ассемблера с языками высокого уровня
- •Использование ассемблера с языками высокого уровня
- •some_proc
- •Главный недостаток этого подхода — сложность создания функции с изменяемым числом параметров, аналогичных
- •Запись some_proc(a,b,c,d,e)
- •some_proc proc push bp
- •some_proc proc
- •эквивалентно
- •Таблица объясняет соглашения о передаче параметров. Например, передача параметров stdcall отличается и от
- •то реально компилятор пишет call _some_proc
- •Пример. C
- •Пример. Pascal
some_proc proc push bp
mov bp,sp ; создать стековый кадр
a equ [bp+4] ; определения параметров b equ [bp+6]
с equ [bp+8] d equ [bp+10] e equ [bp+12]
; текст процедуры, использующей параметры a, b, с, d, e pop bp
ret some_proc endp
Ассемблеры поддерживают и такой формат вызова при
помощи усложненной формы директивы proc с указанием языка С:
some_proc proc |
С,а:word,b:word,с:word,d:word,e:word |
;текст процедуры, использующей параметры a, b, с, d, e.
;Так как BP применяется как указатель стекового кадра,
;его использовать нельзя!
ret some_proc endp
Преимущество по сравнению с PASCAL-конвенцией заключается в том, что освобождение стека от параметров в С возлагается на вызывающую процедуру, что позволяет лучше оптимизировать код программы. Например, если нужно вызвать несколько функций, принимающих одни и те же параметры подряд,
можно не заполнять стек каждый раз заново:
push param2 push param1 call proc1 call proc2 add sp,4
эквивалентно
proc1(param1,param2);
proc2(param1,param2);
и это — одна из причин, почему компиляторы с языка С создают более компактный и быстрый код по сравнению с другими языками.
В таблице ниже представлены основные соглашения по передаче параметров в процедуру.
Соглашение |
Параметры |
Очистка стека |
Регистры |
|
register (fastcall) |
|
|
EAX, EDX, ECX (Delphi) |
|
(быстрый |
Слева направо |
Процедура |
||
ECX, EDX (Visual C++ .NET) |
||||
или регистровый вызов) |
|
|
||
|
|
|
||
pascal |
Слева направо |
Процедура |
Нет |
|
(конвенция языка Паскаль) |
||||
cdecl |
Справа налево |
Вызывающая |
Нет |
|
(конвенция С) |
|
программа |
|
|
stdcall |
Справа налево |
Процедура |
Нет |
|
(стандартный вызов) |
||||
|
|
|
||
Safecall |
Справа налево |
Процедура |
Нет |
Таблица объясняет соглашения о передаче параметров. Например, передача параметров stdcall отличается и от С, и от PASCAL-конвенций. Она применяется для всех системных функций Win32 API. Здесь параметры помещаются в стек в обратном порядке, как в С, но процедуры должны очищать стек сами, как в PASCAL.
Еще одно интересное отклонение от С-конвенции можно наблюдать в Watcom С. Этот компилятор использует регистры для ускорения работы, и параметры в функции передаются по возможности через регистры. Например, при вызове функции
some_proc(a,b,с,d,e,f);
первые четыре параметра передаются соответственно в (Е)АХ, (E)DX, (Е)ВХ, (Е)СХ, а только начиная с пятого, параметры помещают в стек в обычном обратном порядке:
e |
equ |
[bp+4] |
f |
equ |
[bp+6] |
Еще один важный момент - тип возвращаемых функцией данных. С точки зрения ассемблера здесь все просто: в регистре EAX возвращается значение, которое может быть либо числом, либо указателем на переменную или структуру. Если возвращаемое число типа WORD, то оно содержится в младшем слове регистра EAX.
Cогласование имен идентификаторов. Компиляторы Microsoft С (а также многие компиляторы в UNIX) изменяют названия процедур, чтобы отразить способ передачи параметров. Так, к названиям всех процедур, использующих С-конвенцию, приписывается символ подчеркивания. То есть, если в С-программе записано
some_proc();
то реально компилятор пишет call _some_proc
и это означает, что, если эта процедура написана на ассемблере, она должна называться именно _some_proc (или использовать сложную форму записи директивы proc).
Названия процедур, использующих stdcall, например, при создании DLL, искажаются еще более сложным образом: спереди к называнию процедуры добавляется символ подчеркивания, а сзади — символ @ и размер занимаемой параметрами области стека в байтах, (то есть в точности число, стоящее после команды ret в конце процедуры).
some_proc(a:word);
превращается в
Пример. C
int get_seed() |
|
int seed; |
|
{ |
|
_asm { |
|
push |
es |
mov |
ax,0040h |
mov |
es,ax |
mov |
ax,es:[006Ch] |
mov |
seed,ax |
pop |
es |
};
return(seed);
};
В этих ситуациях ассемблерная программа может свободно пользоваться переменными из языка высокого уровня, так как они автоматически преобразуются в соответствующие выражения типа word ptr [bp+4].
Пример. Pascal
function get_seed:longint var
seed:longint begin
asm
push |
es |
mov |
ax,0040h |
mov |
es,ax |
mov |
ax,es:[006Ch] |
mov |
seed,ax |
pop |
es |
end; get_seed:=seed;
end;
