我有两个动态大小的二维数组(猜测是正确的措辞)。我使用以下方法将第一个的内容复制到另一个:
-mutableCopy
有效。但是我无法在asm中重现这一点。我尝试了以下变化无济于事......有人可以启发我......
nonnull
还尝试了LEA(没想到它会工作,因为它应该获取指针地址而不是数组地址),没有工作,并尝试用:
dest:=copy(src,0,4*x*y);
// src,dest:array of array of longint; x,y:longint;
// setlength(both arrays,x,y); //x and y are max 15 bit positive!
提示?顺便说一句,这是delphi 6.错误当然是访问冲突。
答案 0 :(得分:2)
这实际上是一个双重三重问题。
动态数组的结构是什么。
asm中的哪些指令会复制数组。
我在CPU上抛出随机汇编程序,为什么它不起作用?
动态数组的结构
请参阅:http://docwiki.embarcadero.com/RADStudio/Seattle/en/Internal_Data_Formats
引用:
动态数组类型
在32位平台上,动态数组变量占用4个字节的内存(64位上的8个字节),其中包含指向动态分配的数组的指针。当变量为空(未初始化)或保持零长度数组时,指针为零,并且没有动态内存与变量关联。对于非空数组,变量指向动态分配的内存块,除了32位(Win64上的64位)长度指示符和32位引用计数外,还包含该数组。下表显示了动态数组内存块的布局。
动态数组内存布局(32位和64位)
Offset 32-bit -8 -4 0
Offset 64-bit -12 -8 0
contents refcount count start of data
因此动态数组变量是指向上述结构中间的指针。
如何在asm中访问
假设数组包含TMyRec类型的记录
您需要为外部数组中的每个内部数组运行此代码以执行深层复制。我将此作为练习留给读者。 (你可以在pascal中做另一部分)。
type
TDynArr: array of TMyRec;
procedure SlowButBasicMove(const Source: TDynArr; var dest);
asm
//insert register pushes, see below.
mov esi,Source //esi = pointer to source data
mov edi,Dest //edi = pointer to dest
sub esi,8
mov ebx,[esi] //ebx = refcount (just in case)
mov ecx,[esi+4] //ecx = element count
mov edx,SizeOf(TMyRec) //anywhere from 1 to zillions
mul ecx,edx //==ecx=number of bytes in array.
//// now we can start moving
xor ebx,ebx //ebx =0
add eax,8 //eax = @data
@loop:
mov eax,[esi+ebx] //Get data from source
mov [edi+ebx],esi //copy it to dest
add ebx,4 //4 bytes at a time
cmp ebx,ecx //is ebx> number of bytes?
jle loop
//Done copying.
//insert register pops, see below
end;
这是完成的复制,但是为了使系统不崩溃,您需要保存和恢复非易失性寄存器(除了EAX,ECX,EDX之外),请参阅: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 the restoring must happen in the reverse order of the push.
如果你对asm完全陌生,请参阅Jeff Dunteman的书assembly step by step
。
如果出现以下情况,您将获得访问权限:
记住你直接处理CPU。德尔福不会以任何方式为您提供帮助。
真正快速的代码将使用某种形式的SSE在展开的循环中每条指令移动16字节,有关优化汇编程序的示例,请参阅上面提到的fastcode。
随机汇编程序
在汇编程序中,您需要知道完全您要做什么,CPU的工作方式和内容。
设置断点并运行代码。按 ctrl + alt + C 并看到CPU调试窗口。
这将允许您查看Delphi生成的代码
您可以单步执行代码以查看CPU的功能
见:http://www.plantation-productions.com/Webster/index.html
更多阅读。
答案 1 :(得分:0)
动态数组与静态数组不同,特别是涉及多维度时。
有关内部格式,请参阅this reference。
关键是Array Of Array Of LongInt
维度X
和Y
(按此顺序!)是指向X指针数组的指针,指向数组Y LongInts 。
从您的评论中看,您已经为Dest
中的所有元素分配了空间,我假设您要进行深层复制。
这是一个示例程序,为了清楚起见,尽可能简化了装配。
Program Test;
Var Src, Dest: Array Of Array Of LongInt;
X, Y, I, J: Integer;
Begin
X := 4;
Y := 2;
setLength(Src, X, Y);
setLength(Dest, X, Y);
For I := 0 To X-1 Do
For J := 0 To Y-1 Do
Src[I,J] := I*Y + J;
{$ASMMODE intel}
Asm
cld ;Be sure movsd increments the registers
mov esi, DWORD PTR [Src] ;Src pointer
mov edi, DWORD PTR [Dest] ;Dest pointer
mov ecx, DWORD PTR [X] ;Repeat for X times
;The number of elements in Src
@_copy:
push esi ;Save these for later
push edi
push ecx
mov ecx, DWORD PTR [Y] ;Repeat for Y times
;The number of element in a Src[i] array
mov edi, DWORD PTR [edi] ;Get the pointer to the Dest[i] array
mov esi, DWORD PTR [esi] ;Get the pointer to the Src[i] array
rep movsd ;Copy sub array
pop ecx ;Restore
pop edi
pop esi
add esi, 04h ;Go from Src[i] to Src[i+1]
add edi, 04h ;Go from Dest[i] to Dest[i+1]
loop @_copy
End;
For I := 0 To X-1 Do
Begin
WriteLn();
For J := 0 To Y-1 Do
Begin
Write(' ');
Write(Dest[I,J]);
End;
End;
End.
注1 此源代码旨在使用 freepascal 进行编译。
欢迎捐赠 Spare Time(TM)以下载和安装 Delphi !
注意2 此源代码仅用于插图,很明显,上面已经说明了,但不是每个人都知道它。
如果OP想要一种快速复制阵列的方法,他们应该这样说。
注3 我没有保存被破坏的寄存器,这是不良做法,我的不好;我忘记了,因为没有子程序,没有优化,没有理由让编译器在两个寄存器之间的寄存器中传递数据。
这留给读者练习。