Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 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.54 MB
Время: 0.045 c
14-1128009414
Kerk
2005-09-29 19:56
2005.10.30
9 признаков американца (наверно баян)


14-1128525402
***_Diman_***
2005-10-05 19:16
2005.10.30
CeCreateFile - как вызвать?


1-1128767887
Antonn
2005-10-08 14:38
2005.10.30
Ширина выводимого текста на Canvas е


2-1128594808
Del_programmer
2005-10-06 14:33
2005.10.30
строки


8-1118178605
Серёга
2005-06-08 01:10
2005.10.30
Работа с TImage