![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Работа с памятью. ( Выравнивание )
Riply © (2008-03-20 21:50:00)Здравствуйте !
Допустим у нас есть очень привиредливая процедура:
procedure Fastidious(pAligned: Pointer);
Вот подавай ей на входе pAligned выровненный по границе SizeOf(Int64)
иначе она и работать откажется.
И пытаемся мы ее вызвать тремя способами:
procedure TestCallFastidious(pNotAligned: Pointer);
var
//......
MyRecord: TMySuperPuperRecord;
pTmp: Pointer;
begin
//....... 1-й вызов
Fastidious(@MyRecord);
//....... 2-й вызов
pTmp := GetMemory(MemSize);
Fastidious(pTmp);
//....... 3-й вызов
Fastidious(pNotAligned);
end;
Как лучше выкрутиться ?
Для 1-ого и 3-го приходит в голову только
Заводить доп. переменную Pointer и мучаться с перевыделением и копированием.
Со вторым вызовом тоже не понятно.
Мне не удалось получить pTmp не выровненный по 8-байтной границе
и не удалось нигде найти утверждения, что он будет выровнен.
Как с ним обстоят дела ?
P.S.
Пользоваться чем-то вроде VirtualAlloc не хотелось бы.
tesseract (2008-03-20 23:31:00) [21]
> Компилятор может поместить отдельную Filler в пару регистров
> или выкинуть его совсем, а в случае записи он вряд ли догадается
> соптимизировать.
навряд-ли в регистры - он их 32-х считает (Delphi) а int64, как факт, ещё с первых пней идёт.
palva (2008-03-20 23:27:00) [22]
> Вот досада :) Как же тогда исхитриться и объявить "ровно"
> ?
Если palva © (20.03.08 22:21) [2] не подойдет.
то можно исхитриться с промежуточной процедурой на ассемблере.
Где нужно объявить данные? Глобально или в процедуре?
guav (2008-03-20 23:20:00) [23]> var
> Filler: Int64;
> YouParameterData: TFoo;
Если способ с Filler работает, предлагаю
var
R: record
Filler: Int64;
YouParameterData: TFoo;
end;
Компилятор может поместить отдельную Filler в пару регистров или выкинуть его совсем, а в случае записи он вряд ли догадается соптимизировать.
__declspec(align(8)) в Deplhi насколько я знаю нет, есть $ALIGN но это немного не то.
Насчёт второго случая я за [2] или VirtualAlloc.
Насчёт третьего - можно проверить выравнивание, если неправильное, выделить новый буфер, из которого/в который копировать, и свести ко второму.
Riply (2008-03-20 23:12:00) [24]> [15] palva © (20.03.08 23:09)
> Ну значит мне так везет. Я всегда был неудачником :(
Вот досада :) Как же тогда исхитриться и объявить "ровно" ?
tesseract (2008-03-20 23:11:00) [25]
> palva © (20.03.08 23:09) [15]
Выравнивание 8 байт. Или я что-то не понял ?
palva (2008-03-20 23:09:00) [26]
> Предлагается пробовать до первого отрицательного ? :)
Ну значит мне так везет. Я всегда был неудачником :(
{$APPTYPE CONSOLE}
var
Filler: Int64;
YouParameterData: Int64;
begin
WriteLn(Integer(@Filler)); // 4216412
WriteLn(Integer(@YouParameterData)); // 4216420
end.
tesseract (2008-03-20 23:05:00) [27]
> Допустим, я 10 000 раз получила результат, что выровненно.
Win64 - это в принципе 2 среды. Одна 32 бита, вторая 64. И я не уверен что WoW пропустит вызов внутреннего API, через эмулятор. У меня на Win64 вирусы опознаються по ошибкам записи в память.
Riply (2008-03-20 23:02:00) [28]> [11] Игорь Шевченко © (20.03.08 23:00)
> Потому что компилятор размещает данные в порядке объявления.
Тогда, почему первое объявление (Filler: Int64;) выровнено ?
Игорь Шевченко (2008-03-20 23:00:00) [29]Riply © (20.03.08 22:51) [8]
Потому что компилятор размещает данные в порядке объявления.
Riply (2008-03-20 23:00:00) [30]> [10] palva © (20.03.08 22:57)
> Нельзя быть уверенной. Вы больше пробуйте, пробуйте...
Допустим, я 10 000 раз получила результат, что выровненно.
Но ведь это ничего не докажет. (Правда один отрицательный докажет :)
Предлагается пробовать до первого отрицательного ? :)
palva (2008-03-20 22:57:00) [31]
> А почему, при таком объявлении, можно быть уверенной, что
> YouParameterData выровнена ?
>
Нельзя быть уверенной. Вы больше пробуйте, пробуйте...
tesseract (2008-03-20 22:55:00) [32]
> Стандартный GetMem вроде выделяет выровненную память, если
> мне память не изменяет.
Win64 - выделяет выровненную по 4, если не Define-нить.
> Дело в том, что проверка производилась под Win64 (не мною).
Он линейкой проверял ? И именно WoW обошёл ?
Riply (2008-03-20 22:51:00) [33]> [1] Игорь Шевченко © (20.03.08 22:12)
> var
> Filler: Int64;
> YouParameterData: TFoo;
А почему, при таком объявлении, можно быть уверенной, что YouParameterData выровнена ?
Riply (2008-03-20 22:42:00) [34]> [5] palva © (20.03.08 22:29)
> Господь с вами!
Спасибо. Значит я плохо пыталась :)
Riply (2008-03-20 22:40:00) [35]> [3] Игорь Шевченко © (20.03.08 22:25)
> 3-ий способ - ругаться, если приходит извне. Как собственно NT ругается
STATUS_INVALID_PARAMETR
Но, Игорь, это не совсем точно :)
Дело в том, что проверка производилась под Win64 (не мною).
Это самый вероятный вариант, где я спотыкаюсь.
Я излазила MSDN, и единственное объяснение, которое нашла это
данная ошибка при вызове NtQueryInformationFile(...FileStreamInformation...).
Проверить не могу так как у меня нет доступа к Win64
palva (2008-03-20 22:29:00) [36]
> Мне не удалось получить pTmp не выровненный по 8-байтной
> границе
Господь с вами!
{$APPTYPE CONSOLE}
var
i1: Pointer;
i2: Pointer;
i3: Pointer;
begin
i1 := GetMemory(4);
i2 := GetMemory(4);
i3 := GetMemory(4);
WriteLn(Integer(i1)); // 8585220
WriteLn(Integer(i2)); // 8585232
WriteLn(Integer(i3)); // 8585244
end.
Игорь Шевченко (2008-03-20 22:26:00) [37]
> Со вторым вызовом тоже не понятно.
Стандартный GetMem вроде выделяет выровненную память, если мне память не изменяет.
Игорь Шевченко (2008-03-20 22:25:00) [38]3-ий способ - ругаться, если приходит извне. Как собственно NT ругается
palva (2008-03-20 22:21:00) [39]Выделить на 8 байтов больше чем надо, а потом выровнять.
Игорь Шевченко (2008-03-20 22:12:00) [40]
> Вот подавай ей на входе pAligned выровненный по границе
> SizeOf(Int64)
> иначе она и работать откажется.
> И пытаемся мы ее вызвать тремя способами:
var
Filler: Int64;
YouParameterData: TFoo;