Текущий архив: 2005.10.30;
Скачать: CL | DM;
ВнизНепонятки с адресацией Найти похожие ветки
← →
DMitryFox (2005-08-24 15:31) [0]Люди подскажите, почему может не работать нижеследующий код и как можно исправить ситуацию:
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
ptest: pointer;
end;
.....
procedure TForm1.FormCreate(Sender: TObject);
begin
ptest := VirtualAlloc(0, $100, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
asm
xorps xmm0, xmm0
mov [eax], ptest
movapd [eax], xmm0 // ERROR !!! Access Violation!!!
end;
end;
Причем, еслиptest := VirtualAlloc.....
Перенести в процедуру Button1Click, то все работает нормально.
Иными словами, мне необходимо при создании объекта навыделять памяти через VirtualAlloc для дальнейшего использования в разных методах...
Спасибо
← →
begin...end © (2005-08-24 15:38) [1]> DMitryFox (24.08.05 15:31)
> mov [eax], ptest
Поясните это. Разве перед выполнением этой строки содержимое EAX не равно нулю?
← →
DMitryFox (2005-08-24 15:39) [2]сорри еах без скобок, но всерно не работает
mov eax, ptest
← →
Digitman © (2005-08-24 15:40) [3]
> мне необходимо .. навыделять памяти через
> VirtualAlloc
чем тебе GetMem не угодил ?
что за велосипед ?
← →
DMitryFox (2005-08-24 15:50) [4]getmem не подходит для использования с SSE,т.к. возвращает не выровненные 16 значения адресов...
← →
DMitryFox (2005-08-24 15:55) [5]Пофигу, с GetMem всерно не пашет, даже без использования SEE
asm
mov eax, ptest
mov [eax], ebx // Access Violation...
end;
Посмотрел как делает компилятор, если прописать:asm
mov eax, [ebp-$04]
mov eax, [eax + ptest]
xorps xmm0, xmm0
movapd [eax], xmm0
end;
Может кто-нибуть пояснить, плиз ?
← →
Digitman © (2005-08-24 15:56) [6]
> не выровненные 16 значения адресов
эт чего такое ? что за галиматья ?
говори по-русски - выравнивание на границу "слова" КАКОЙ разрядности тебе нужно ? 32 ? 64 ?
← →
Digitman © (2005-08-24 16:17) [7]особо радует перемещение сабжа в "WinAPI" - именно в WinAPI и следует искать ответ на вопрос.
← →
DMitryFox (2005-08-24 16:24) [8]
> эт чего такое ? что за галиматья ?
>
> говори по-русски - выравнивание на границу "слова" КАКОЙ
> разрядности тебе нужно ? 32 ? 64 ?
{$ALIGN 16} нужен.
но в D7 такого нет...
← →
Digitman © (2005-08-24 16:30) [9]
> {$ALIGN 16} нужен
не надо цитировать "умные слова" !
выравнивание на границу слова КАКОЙ разрядности тебе требуется ?!
← →
Игорь Шевченко © (2005-08-24 16:33) [10]
> Может кто-нибуть пояснить, плиз ?
Конечно может. Этот "кто-то" называется отладчик.
← →
DMitryFox (2005-08-24 16:34) [11]I>
> выравнивание на границу слова КАКОЙ разрядности тебе требуется
> ?!
SSE требует для работы выравнивание данных на 16 байт - что тут непонятного...
← →
alpet © (2005-08-24 16:48) [12]DMitryFox (24.08.05 16:34) [11]
Попробуй посмотреть в Watch какое значение получается в регистре eax, и насколько оно отличается от ptest.
procedure TForm1.Set1;
asm
mov eax, [self.ptest]
mov dword ptr [eax], 1
end;
← →
Digitman © (2005-08-24 16:48) [13]не вижу проблем.
- выдели с пом. GetMem() блок памяти размером не меньшим чем (n + 1) * 16байт
- для полученного адреса предоставленного тебе менеджером памяти блока расчитай/найди первый же адрес кратный 16-ти
← →
alpet © (2005-08-24 16:50) [14]Кстати - при использовании VirtualAlloc нет смысла выделять меньше страницы памяти (4Кбайт).
← →
DMitryFox (2005-08-24 16:52) [15]
> не вижу проблем.
>
> - выдели с пом. GetMem() блок памяти размером не меньшим
> чем (n + 1) * 16байт
>
> - для полученного адреса предоставленного тебе менеджером
> памяти блока расчитай/найди первый же адрес кратный 16-ти
Нафига мне это делать, если я могу спокойно пользоваться VirtualAlloc ? что и делаю... вопрос в другом, см первый пост.
Почему я из асма в другом методе не могу достучаться напрямую до указателя ?
← →
DMitryFox (2005-08-24 16:54) [16]
> Конечно может. Этот "кто-то" называется отладчик.
Он может ответить на вопрос, почему вместо одной командыmov eax, ptest
я должен использовать наворотmov eax, [bp - 4]
mov eax, [eax + ptest]
что за адрес содержится в ptest ?
что лежит на стеке-4 ?
← →
alpet © (2005-08-24 16:58) [17]DMitryFox (24.08.05 16:52) [15]
program temp;
uses Windows;
type TClass1 = class
public
ptest: Pointer;
constructor Create;
destructor Destroy; override;
procedure Test;
end;
{ TClass1 }
constructor TClass1.Create;
begin
ptest := VirtualAlloc (nil, 4096, MEM_COMMIT, PAGE_READWRITE);
end;
destructor TClass1.Destroy;
begin
VirtualFree (ptest, 4096, MEM_DECOMMIT);
end;
procedure TClass1.Test;
asm
push ebx
push edx
mov ebx, ptest
mov edx, [ptest] ; cause av
mov eax, [self.ptest] ; yes is right!
test eax, eax
pop edx
pop ebx
end;
var c: TClass1;
begin
c := TClass1.Create;
c.Test;
c.Free;
end.
Compiler results:
mov ebx, ptest
mov ebx, $00000004
mov edx, [ptest] ; cause av
mov edx, [$00000004]
mov eax, [self.ptest] ; yes is right!
mov eax, [eax + $00000004]
....
← →
Digitman © (2005-08-24 17:20) [18]
> Нафига мне это делать, если я могу спокойно пользоваться
> VirtualAlloc ?
нафига тебе VirtualAlloc, если ты тоже самое можешь реализовать НЕ выходя за рамки ОР ?
если ты НЕ в состоянии расчитать требуемые в дан.случае для GetMem()параметры, то нехрена тебе делать в WinAPI.
← →
icWasya © (2005-08-24 17:23) [19]По умолчанию напрямую можно обращаться только к глобальным переменным и к локальным данным и параметрам текущей процедуры. К полям объекта доступ идёт через косвенную адресацию.
Скорее всего везде, где есть обращение к полям TForm1 нужно вместо
asm
...
mov eax, ptest
...
end;
писать
asm
...
mov ebx, self
mov eax, TForm1([ebx]).ptest; // что бы точно понимать, что же мы делаем
...
end;
Кроме того, надо помнить, что по умолчанию несколько параметров передаются через регистры. В данном случае
procedure TForm1.Button1Click(Sender: TObject);
- метод с одним параметром - Self=EAX, Sender=EDX;
При входе в процедуру скорее всего эти регистры будут сохранены, но оптимизатор может думать по другому - если не найдёт явного использования Self, то EAX сохраняться не будет, и придётся это делать самому, например, используя не ячейку в стеке, а какой нибудь регистр.
procedure TForm1.Button1Click(Sender: TObject);
asm
mov ebx,eax; // сохраняем
xorps xmm0, xmm0
//mov [eax], ptest
mov eax, TForm1([ebx]).ptest;
movapd [eax], xmm0 //
end;
← →
DMitryFox (2005-08-24 17:23) [20]
> procedure TClass1.Test;
> asm
> push ebx
> push edx
> mov ebx, ptest
> mov edx, [ptest] ; cause av
> mov eax, [self.ptest] ; yes is right!
> test eax, eax
> pop edx
> pop ebx
> end;
Работает - все круто.
пробую:procedure TForm1.FormCreate(Sender: TObject);
begin
ptest := VirtualAlloc(0, $100, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
asm
mov ecx, self.ptest
xorps xmm0, xmm0
movapd [ecx], xmm0 // Access violation !!!
end;
end;
Причем если ptest объявить в процедуре, то все работает...
Пробую дальше:asm
mov eax, [ebp-4]
mov eax, [eax+ptest]
mov ecx, self.ptest
movapd [eax], xmm0 // yes is right ;)
movapd [ecx], xmm0 // Access violation...
end;
значения еах и есх - разные, ptest объявлена в классе...
← →
alpet © (2005-08-24 17:32) [21]Есть такой указатель self, что на данные твоего обьекта указывает. При вызове метода класса он передается, как ни странно в eax. Обращение [self.ptest] (или self.ptest) компилятор преобразует соответственно в [eax + ptest]. Поэтому ты должен беречь содержимое этого регистра, а не травмировать.
{ ptest = $B100000 }
mov eax, [eax+ptest] // eax = self
mov eax, [eax + 4] // eax = ptest
mov ecx, self.ptest // eax is not self !!!
mov ecx, [eax + 4] // ecx = ???? PDWORD (ecx)^ may be 0
mov edx, [ecx] // cause av
← →
DMitryFox (2005-08-24 17:53) [22]
> Есть такой указатель self, что на данные твоего обьекта
> указывает. При вызове метода класса он передается, как ни
> странно в eax. Обращение [self.ptest] (или self.ptest) компилятор
> преобразует соответственно в [eax + ptest]. Поэтому ты должен
> беречь содержимое этого регистра, а не травмировать.
Можно смело травмировать eax:
mov ebx, self
mov ebx, [ebp-4]
mov ecx, TForm1([ebx]).ptest
mov ecx, [ebx+$00002fc]
Судя по коду указатель на self можно достать со стека
← →
alpet © (2005-08-24 18:13) [23]DMitryFox (24.08.05 17:53) [22]
Переменная self в стеке присутствует в случае использования:
procedure TForm1.Func1;
begin
asm
mov ebx, self // mov ebx, [ebp - 4]
...
end;
end;
и в eax, если тело функции состоит целиком из inline-assembler.
procedure TForm1.Func1;
asm
mov ebx, self
end;
потому что
begin компилируется в код пролога функции:
push ebp ;; save ebp
mov ebp, esp ;; set to stack ptr
push ecx ;; allocate 4 bytes in stack
mov [ebp - 4], eax ;; save eax to local var "self"
Но уже плюс что разобрался ;)
← →
DMitryFox (2005-08-24 18:17) [24]
> нафига тебе VirtualAlloc, если ты тоже самое можешь реализовать
> НЕ выходя за рамки ОР ?
>
> если ты НЕ в состоянии расчитать требуемые в дан.случае
> для GetMem()параметры, то нехрена тебе делать в WinAPI.
Так что-ли ?
ptest := GetMemory($100);
integer(ptest) := ((integer(ptest) + 15) div 16) * 16;
или наверное понятнее будет:ptest := GetMemory($100);
ptest := pointer(((integer(ptest) + 15) div 16) * 16);
не, мне больше нравится так:
ptest := GetMemory($100);
while (integer(ptest) mod 16) <> 0 do
inc(integer(ptest));
;)
← →
alpet © (2005-08-24 18:39) [25]DMitryFox (24.08.05 18:17) [24]
А где HeapAlloc? :)
← →
DMitryFox (2005-08-24 18:53) [26]
> alpet © (24.08.05 18:39) [25]
>
> А где HeapAlloc? :)
А что это ? сорри, чайник я...
пойду срочно Фаронова почитаю :)
← →
DMitryFox (2005-08-24 19:28) [27]Всем спасбо, вроде во всем, что интерисовало разобрался
Страницы: 1 вся ветка
Текущий архив: 2005.10.30;
Скачать: CL | DM;
Память: 0.52 MB
Время: 0.043 c