Выравнивание стека и вызов АПИ x64

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Ответить
myles
незнакомец
Сообщения: 8
Зарегистрирован: 09.03.2012 20:12:15

Выравнивание стека и вызов АПИ x64

Сообщение myles »

Встретился к своему сожалению в багом, описываю:

v

Код: Выделить всё

ar ...

procedure f1;
var ...
begin
 p :=MapViewOfFile(hMap ,FILE_MAP_ALL_ACCESS,0,0,SIZE_1);
end;

И эта штука рабоатет в зависимости от того, выравнен ли стек на границу 0x20 !!

То есть пишу прогу, она работает. Далее если описываю в переменных процедуры перемунную и юзаю ее, то на момент вызова сбивается стек (а он выравнен по 0х10). Итого получается что мне нужно внимательно следить за тем, чтобы на момент вызова АПИ был выравнен стек, и если у меня в процедуре или функции размер моих переменных на кратен 0x20, то мне прийдется добавлять "пустые" переменные.. чтобы самостоятельно выравнять стек?

Есть ли может какой способ или директива по автовыравниванию стека в функциях?

(актуально для х64)
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
Сообщения: 1409
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Sergei I. Gorelkin »

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

Выравнивание стека на 16 байт, требуемое x86_64, осуществляется само по себе без всяких директив. Других требований к выравниванию со сторны ABI нет.
myles
незнакомец
Сообщения: 8
Зарегистрирован: 09.03.2012 20:12:15

Сообщение myles »

Тут можно поподробнее?
Здесь скорее забыто разыменование какого-нибудь указателя, или взятие адреса, что приводит к порче стека.




У меня дело так:

Код: Выделить всё

type 
 TMapViewOfFile= function(hFileMappingObject: THandle; dwDesiredAccess: DWORD;
  dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap: DWORD): Pointer; stdcall;

var MapViewOfFile:TMapViewOfFile;
..
Pointer(MapViewOfFile):=GetProcAddress...
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
Сообщения: 1409
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Sergei I. Gorelkin »

myles писал(а):Тут можно поподробнее?

Например, вместо ReadFile(hFile, p^, ...) написано ReadFile(hFile, p, ...), причем где-нибудь совсем в другом месте программы. Данные читаются не туда, куда указывает p, а прямо в стек. Подробнее по приведенным отрывкам сказать ничего нельзя.

myles писал(а):type TMapViewOfFile= function(hFileMappingObject: THandle; dwDesiredAccess: DWORD;  dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap: DWORD): Pointer; stdcall;


Тут последний параметр (dwNumberOfBytesToMap) должен быть типа size_t.
myles
незнакомец
Сообщения: 8
Зарегистрирован: 09.03.2012 20:12:15

Сообщение myles »

Например, вместо ReadFile(hFile, p^, ...) написано ReadFile(hFile, p, ...), причем где-нибудь совсем в другом месте программы. Данные читаются не туда, куда указывает p, а прямо в стек.


Что значит: "данные читаются не туда. куда указывает р, а прямо в стек"?
Вообще если изучить описание функции ReadFile, то вторым параметром будет указатель на буфер с данными, как и везде.
И получается, что в случае 32 бит в стек положится указатель на данные, а не сами данные!
В 64 бит картина другая. т.к. первеы 4 параметра передаются через регистры rcx, rdx, r8, r9, а остальные через стек, но и в этом случае будет передан указатель на буфер, но никак не сам буфер.
Далее, (беру Делфи, но и в Лазарусе така же штука)

Описание функций будут идентичные:

Код: Выделить всё

function f1(pDW:PDWORD)....

function f1(var dw:dword)...


Единственная разница - в самом теле функции синтаксис будет pDW^:= или просто dw:=
Но если посмотреть в отадочнике - будет точно такой же код - передача указателей.

Аналогичныеми будут конструкции:

Код: Выделить всё

function f21(p :Pointer)....

function f22(b:buffer)...

Вызываем их:

Код: Выделить всё

var buff:array [0..127] of char;
pn:pointer;
..
f21(@buff);

pn:=@buff;
f22(buff);
f22(pn^);


Двоичный код получиться одинаковый. а штука ReadFile(hFile, p, ...) либо не откампилируется, либо будет падать программа, т.к. буфер будет записан в стек и перетрет адреса возврата и другие переменные..

Тут последний параметр (dwNumberOfBytesToMap) должен быть типа size_t.

А вот эта штука уже более вероятна, т.к. неизвестно что будет в старшем двойном слове.
Ответить