delphi - Inline asm (32) emulation of move (copy memory) command -
i have 2 two-dimensional arrays dynamic sizes (guess that's proper wording). copy content of first 1 other using:
dest:=copy(src,0,4*x*y); // src,dest:array of array of longint; x,y:longint; // setlength(both arrays,x,y); //x , y max 15 bit positive!
it works. i'm unable reproduce in asm. tried following variations no avail... enlighten me...
mov esi,src; mov edi,dest; mov ebx,y; mov eax,x; mul ebx; push ds; pop es; mov ecx,eax; cld; rep movsd;
also tried lea (didn't expect work since should fetch pointer address not array address), no workie, , tried with:
p1:=@src[0,0]; p2:=@dest[0,0]; //being no-type pointers mov esi,p1; mov edi,p2... (the same asm)
hints pls? btw it's delphi 6. error is, of course, access violation.
this two-fold three-fold question.
what's structure of dynamic array.
which instructions in asm copy array.
i'm throwing random assembler @ cpu, why doesn't work?
structure of dynamic array
see: http://docwiki.embarcadero.com/radstudio/seattle/en/internal_data_formats quote:
dynamic array types
on 32-bit platform, dynamic-array variable occupies 4 bytes of memory (and 8 bytes on 64-bit) contain pointer dynamically allocated array. when variable empty (uninitialized) or holds zero-length array, pointer nil , no dynamic memory associated variable. nonempty array, variable points dynamically allocated block of memory contains array in addition 32-bit (64-bit on win64) length indicator , 32-bit reference count. table below shows layout of dynamic-array memory block.
dynamic array memory layout (32-bit , 64-bit)
offset 32-bit -8 -4 0 offset 64-bit -12 -8 0 contents refcount count start of data
so dynamic array variable pointer middle of above structure.
how access in asm
let's assume array holds records of type tmyrec
you'll need run code every inner array in outer array deep copy. leave exercise reader. (you can other part in pascal).
type tdynarr: array of tmyrec; procedure slowbutbasicmove(const source: tdynarr; var dest); asm //insert register pushes, see below. mov esi,source //esi = pointer source data mov edi,dest //edi = pointer dest sub esi,8 mov ebx,[esi] //ebx = refcount (just in case) mov ecx,[esi+4] //ecx = element count mov edx,sizeof(tmyrec) //anywhere 1 zillions mul ecx,edx //==ecx=number of bytes in array. //// can start moving xor ebx,ebx //ebx =0 add eax,8 //eax = @data @loop: mov eax,[esi+ebx] //get data source mov [edi+ebx],esi //copy dest add ebx,4 //4 bytes @ time cmp ebx,ecx //is ebx> number of bytes? jle loop //done copying. //insert register pops, see below end;
that's copy done, in order system not crash, need save , restore non volatile registers (all eax, ecx, edx), see: http://docwiki.embarcadero.com/radstudio/seattle/en/program_control
push ebx push esi push edi --- insert code shown above //restore non-volatile registers pop edi pop esi pop ebx //note restoring must happen in reverse order of push.
see jeff dunteman's book assembly step step
if you're new asm.
you access violations if:
- you try read wrong address.
- you try write wrong adress.
- you read past end of array.
- you write memory haven't claimed before using getmem or whatever means.
- if write past end of buffer.
- if not restore non-volatile registers
remember you're directly dealing cpu. delphi not assist in way.
really fast code use form of sse move 16bytes per instruction in unrolled loop, see above mentioned fastcode examples of optimized assembler.
random assembler
in assembler need know exactly you're do, how , cpu does.
set breakpoint , run code. press ctrl + alt + c , behold cpu-debug window.
allow see code delphi generates.
can single step through code see cpu does.
see: http://www.plantation-productions.com/webster/index.html
more reading.
Comments
Post a Comment