![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Непонятки с адресацией
DMitryFox © (2005-08-24 15:31:00)Люди подскажите, почему может не работать нижеследующий код и как можно исправить ситуацию:
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 для дальнейшего использования в разных методах...
Спасибо
DMitryFox (2005-08-24 19:28:00) [1]Всем спасбо, вроде во всем, что интерисовало разобрался
DMitryFox (2005-08-24 18:53:00) [2]
> alpet © (24.08.05 18:39) [25]
>
> А где HeapAlloc? :)
А что это ? сорри, чайник я...
пойду срочно Фаронова почитаю :)
alpet (2005-08-24 18:39:00) [3]DMitryFox (24.08.05 18:17) [24]
А где HeapAlloc? :)
DMitryFox (2005-08-24 18:17:00) [4]
> нафига тебе 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:13:00) [5]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 17:53:00) [6]
> Есть такой указатель 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 17:32:00) [7]Есть такой указатель 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:23:00) [8]
> 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 объявлена в классе...
icWasya (2005-08-24 17:23:00) [9]По умолчанию напрямую можно обращаться только к глобальным переменным и к локальным данным и параметрам текущей процедуры. К полям объекта доступ идёт через косвенную адресацию.
Скорее всего везде, где есть обращение к полям 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;
Digitman (2005-08-24 17:20:00) [10]
> Нафига мне это делать, если я могу спокойно пользоваться
> VirtualAlloc ?
нафига тебе VirtualAlloc, если ты тоже самое можешь реализовать НЕ выходя за рамки ОР ?
если ты НЕ в состоянии расчитать требуемые в дан.случае для GetMem()параметры, то нехрена тебе делать в WinAPI.
alpet (2005-08-24 16:58:00) [11]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]
....
DMitryFox (2005-08-24 16:54:00) [12]
> Конечно может. Этот "кто-то" называется отладчик.
Он может ответить на вопрос, почему вместо одной команды
mov eax, ptestя должен использовать наворот
mov eax, [bp - 4]
mov eax, [eax + ptest]
что за адрес содержится в ptest ?
что лежит на стеке-4 ?
DMitryFox (2005-08-24 16:52:00) [13]
> не вижу проблем.
>
> - выдели с пом. GetMem() блок памяти размером не меньшим
> чем (n + 1) * 16байт
>
> - для полученного адреса предоставленного тебе менеджером
> памяти блока расчитай/найди первый же адрес кратный 16-ти
Нафига мне это делать, если я могу спокойно пользоваться VirtualAlloc ? что и делаю... вопрос в другом, см первый пост.
Почему я из асма в другом методе не могу достучаться напрямую до указателя ?
alpet (2005-08-24 16:50:00) [14]Кстати - при использовании VirtualAlloc нет смысла выделять меньше страницы памяти (4Кбайт).
Digitman (2005-08-24 16:48:00) [15]не вижу проблем.
- выдели с пом. GetMem() блок памяти размером не меньшим чем (n + 1) * 16байт
- для полученного адреса предоставленного тебе менеджером памяти блока расчитай/найди первый же адрес кратный 16-ти
alpet (2005-08-24 16:48:00) [16]DMitryFox (24.08.05 16:34) [11]
Попробуй посмотреть в Watch какое значение получается в регистре eax, и насколько оно отличается от ptest.
procedure TForm1.Set1;
asm
mov eax, [self.ptest]
mov dword ptr [eax], 1
end;
DMitryFox (2005-08-24 16:34:00) [17]I>
> выравнивание на границу слова КАКОЙ разрядности тебе требуется
> ?!
SSE требует для работы выравнивание данных на 16 байт - что тут непонятного...
Игорь Шевченко (2005-08-24 16:33:00) [18]
> Может кто-нибуть пояснить, плиз ?
Конечно может. Этот "кто-то" называется отладчик.
Digitman (2005-08-24 16:30:00) [19]
> {$ALIGN 16} нужен
не надо цитировать "умные слова" !
выравнивание на границу слова КАКОЙ разрядности тебе требуется ?!
DMitryFox (2005-08-24 16:24:00) [20]
> эт чего такое ? что за галиматья ?
>
> говори по-русски - выравнивание на границу "слова" КАКОЙ
> разрядности тебе нужно ? 32 ? 64 ?
{$ALIGN 16} нужен.
но в D7 такого нет...