gpt4 book ai didi

arrays - 汇编器数组最大元素搜索

转载 作者:行者123 更新时间:2023-12-03 15:55:03 24 4
gpt4 key购买 nike

我需要在Delphi中编写asm函数来搜索最大数组元素。这就是我写的。这里几乎没有问题。

第一 - mov ecx, len只是在这里没有以正确的方式工作。实际上它替换了 ECX 中的值但不具有 len 中的值!如果我只写一个例子 mov ecx, 5 ecx 中出现 5。

第二 - 我在 5 个元素的数组上测试此函数(使用 mov ecx, 5 ofc ),它返回一些奇怪的结果。我想也许是因为我在尝试像这样读取数组 0 元素时做了一些磨损

mov edx, arr
lea ebx, dword ptr [edx]

但是如果我这样读

  lea ebx, arr

它说操作无效,如果我这样尝试

lea bx, arr

它说尺寸不匹配。

我该如何解决这个问题?完整代码在这里:

 program Project2;

{$APPTYPE CONSOLE}

uses
SysUtils;

Type
TMyArray = Array [0..255] Of Byte;



function randArrCreate(len:Integer):TMyArray;
var temp:TMyArray; i:Integer;
begin
Randomize;
for i:=0 to len-1 do
temp[i]:=Random(100);
Result:= temp;
end;

procedure arrLoop(arr:TMyArray; len:Integer);
var i:integer;
begin
for i:=0 to len-1 do begin
Write(' ');
Write(arr[i]);
Write(' ');
end;
end;

function arrMaxAsm(arr:TMyArray; len:integer):Word; assembler;
asm
mov edx, arr
lea ebx, dword ptr [edx]
mov ecx, len
xor ax,ax //0
mov ax, [ebx] //max

@cycle:
mov dx, [ebx]
cmp dx, ax
jg @change
jmp @cont
@change:
mov ax, dx
@cont:
inc ebx
loop @cycle

mov result, ax
end;


var massive:TMyArray; n,res:Integer;
begin
Readln(n);
massive:=randArrCreate(n);//just create random array
arrLoop(massive,n);//just to show what in it
res:=arrMaxAsm(massive, n);
Writeln(res);
Readln(n);
end.

最佳答案

首先,调用约定:什么数据被发送到函数以及在哪里?

根据the documentation ,数组作为 32 位指针传递到数据,整数作为值传递。

根据相同的文档,支持多种调用约定。不幸的是,默认的没有记录 - 明确指定一个将是一个好主意。

根据您的描述,mov ecx, len不起作用,我猜测编译器默认使用register约定,并且参数已经放置在 ecxedx 中,然后您的代码将它们混合在一起。您可以更改代码以使用该约定,或者告诉编译器使用堆栈传递参数 - 使用 stdcall 约定。我随意选择了第二个选项。无论您选择哪一个,请确保明确指定调用约定。

<小时/>

接下来是实际的函数逻辑。

  1. 您使用 16 位寄存器而不是完整的 32 位寄存器有什么原因吗?
  2. 您的数组包含字节,但您正在读取和比较单词。
  3. lea ebx, dword ptr [edx]mov ebx, edx 相同。您只是引入了另一个临时变量。
  4. 您正在比较元素,就像它们已签名一样。
  5. 现代编译器倾向于在不使用loop的情况下实现循环。
  6. 文档还说需要保留 ebx - 因为函数使用了 ebx,所以需要在开始时保存其原始值并在之后恢复。<
<小时/>

这就是我重写你的函数的方式(使用 Lazarus ,因为我大约 8 年没有接触过 Delphi - 没有编译器可以实现):

function arrMaxAsm(arr:TMyArray; len:integer):Word; assembler; stdcall;
asm
push ebx { save ebx }

lea edx, arr { Lazarus accepts a simple "mov edx, arr" }
mov edx, [edx] { but Delphi 7 requires this indirection }

mov ecx, len
xor ax, ax { set default max to 0 }
test ecx, ecx
jle @done { if len is <= 0, nothing to do }
movzx ax, byte ptr [edx] { read a byte, zero-extend it to a word }
{ and set it as current max }

@cont:
dec ecx
jz @done { if no elements left, return current max }

@cycle:
inc edx
movzx bx, byte ptr [edx] { read next element, zero-extend it }
cmp bx, ax { compare against current max as unsigned quantities }
jbe @cont
mov ax, bx
jmp @cont

@done:
pop ebx { restore saved ebx }
mov result, ax
end;

可以通过重新组织循环跳转来进一步优化它 - YMMV。

<小时/>

注意:这仅适用于字节大小的无符号值。为了使其适应不同大小/符号的值,需要进行一些更改:

数据大小:

  1. 读取正确的字节数:
    movzx bx, byte ptr [edx]  { byte-sized values }

mov bx, word ptr [edx] { word-sized values }

mov ebx, dword ptr [edx] { dword-sized values }
{ note that the full ebx is needed to store this value... }

请注意,此读取是在两个地方完成的。如果您处理的是双字,您还需要将结果从 ax 更改为 eax

  1. 提前超过正确的字节数。
     @cycle:
inc edx { for an array of bytes }

add edx, 2 { for an array of words }

add edx, 4 { for an array of dwords }

处理有符号值:

  1. 值扩展(如果应用)需要从 movzx 更改为 movsx

  2. 需要调整设置新最大值之前的条件跳转:

      cmp bx, ax         { compare against current max as unsigned quantities }
jbe @cont

cmp bx, ax { compare against current max as signed quantities }
jle @cont

关于arrays - 汇编器数组最大元素搜索,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13430389/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com