Function Delphi-编写一个带有函数的.pas库
我正在用汇编语言在Delphi中编写一些函数。所以我想把它放在一个名为Function Delphi-编写一个带有函数的.pas库,function,delphi,assembly,Function,Delphi,Assembly,我正在用汇编语言在Delphi中编写一些函数。所以我想把它放在一个名为Strings.pas的.pas文件中。要在中使用,请使用新Delphi软件的。我需要写什么才能使它成为有效的库? 我的功能是这样的: function Strlen(texto : string) : integer; begin asm mov esi, texto xor ecx,ecx cld @here: inc ecx lodsb cmp al,0
Strings.pas
的.pas文件中。要在中使用,请使用新Delphi软件的。我需要写什么才能使它成为有效的库?
我的功能是这样的:
function Strlen(texto : string) : integer;
begin
asm
mov esi, texto
xor ecx,ecx
cld
@here:
inc ecx
lodsb
cmp al,0
jne @here
dec ecx
mov Result,ecx
end;
end;
它计算字符串中的字符数。如何在libStrings中创建它。使用调用pas
使用字符串代码>在我的表单中?一个.pas
文件是一个单元,而不是库。.pas
文件需要有单元
、接口
和实现
语句,例如:
Strings.pas:
unit Strings;
interface
function Strlen(texto : string) : integer;
implementation
function Strlen(texto : string) : integer;
asm
// your assembly code...
// See Note below...
end;
end.
然后,您可以将.pas
文件添加到其他项目中,并根据需要使用字符串单元。它将直接编译到每个可执行文件中。你不需要用它建立一个单独的图书馆。但是如果你想,你可以。创建一个单独的库(DLL)或包(BPL)项目,将.pas文件添加到其中,并将其编译成可执行文件,然后在其他项目中引用
对于DLL库,您将无法直接使用字符串单元。您必须从库中导出
您的函数(并且字符串
不是安全的数据类型,无法在模块之间传递DLL边界),例如:
Mylib.dpr:
library Mylib;
uses
Strings;
exports
Strings.Strlen;
begin
end.
然后,您可以让其他项目使用引用DLL文件的external
子句声明函数,例如:
function Strlen(texto : PChar) : integer; external 'Mylib.dll';
在这种情况下,您可以制作一个包装器.pas
文件,声明要导入的函数,将该单元添加到其他项目中,并根据需要使用它,例如:
StringsLib.pas:
unit StringsLib;
interface
function Strlen(texto : PChar) : integer;
implementation
function Strlen; external 'Mylib.dll';
end.
对于包,您可以直接使用字符串单元。只需在项目经理的其他项目需求列表中添加对包的.bpi
的引用,然后根据需要使用该单元。在这种情况下,string
可以安全地传递
注意:在您显示的汇编代码中,为了使函数不会导致访问冲突,您需要保存并恢复ESI
寄存器。请参阅Delphi文档中关于的部分 正确的asm版本可能是:
unit MyStrings; // do not overlap Strings.pas unit
interface
function StringLen(const texto : string) : integer;
implementation
function StringLen(const texto : string) : integer;
asm
test eax,eax
jz @done
mov eax,dword ptr [eax-4]
@done:
end;
end.
请注意:
- 我使用
MyStrings
作为单元名,因为重叠官方RTL单元名是一个非常糟糕的主意,比如Strings.pas
李>
- 我编写了
(const texto:string)
而不是(texto:string)
,以避免调用时引用计数发生变化李>
- Delphi
string
type已经将其长度存储为integer
,就在字符内存缓冲区之前李>
- 在Delphi asm调用约定中,输入参数在
eax edx ecx
寄存器中设置,函数的整数结果是eax
寄存器-请参阅李>
- 我测试了
texto
是否为nil
(eax=0
),它表示无效的'
字符串李>
- 这只能在Win32下工作-Win64下的asm代码将是多样的李>
- 内置的
length()李>
- 注意潜在的名称冲突:已经有一个众所周知的
StrLen()
函数,它需要一个PChar
作为输入参数-因此我将您的函数重命名为StringLen()
由于您想学习asm,下面是该函数的一些参考实现
面向快速PChar
的版本可能是:
function StrLen(S: PAnsiChar): integer;
asm
test eax,eax
mov edx,eax
jz @0
xor eax,eax
@s: cmp byte ptr [eax+edx+0],0; je @0
cmp byte ptr [eax+edx+1],0; je @1
cmp byte ptr [eax+edx+2],0; je @2
cmp byte ptr [eax+edx+3],0; je @3
add eax,4
jmp @s
@1: inc eax
@0: ret
@2: add eax,2; ret
@3: add eax,3
end;
更优化的版本:
function StrLen(S: PAnsiChar): integer;
// pure x86 function (if SSE2 not available) - faster than SysUtils' version
asm
test eax,eax
jz @@z
cmp byte ptr [eax+0],0; je @@0
cmp byte ptr [eax+1],0; je @@1
cmp byte ptr [eax+2],0; je @@2
cmp byte ptr [eax+3],0; je @@3
push eax
and eax,-4 { DWORD Align Reads }
@@Loop:
add eax,4
mov edx,[eax] { 4 Chars per Loop }
lea ecx,[edx-$01010101]
not edx
and edx,ecx
and edx,$80808080 { Set Byte to $80 at each #0 Position }
jz @@Loop { Loop until any #0 Found }
@@SetResult:
pop ecx
bsf edx,edx { Find First #0 Position }
shr edx,3 { Byte Offset of First #0 }
add eax,edx { Address of First #0 }
sub eax,ecx { Returns Length }
@@z: ret
@@0: xor eax,eax; ret
@@1: mov eax,1; ret
@@2: mov eax,2; ret
@@3: mov eax,3
end;
function StrLen(S: PAnsiChar): integer;
asm // from GPL strlen32.asm by Agner Fog - www.agner.org/optimize
or eax,eax
mov ecx,eax // copy pointer
jz @null // returns 0 if S=nil
push eax // save start address
pxor xmm0,xmm0 // set to zero
and ecx,0FH // lower 4 bits indicate misalignment
and eax,-10H // align pointer by 16
movdqa xmm1,[eax] // read from nearest preceding boundary
pcmpeqb xmm1,xmm0 // compare 16 bytes with zero
pmovmskb edx,xmm1 // get one bit for each byte result
shr edx,cl // shift out false bits
shl edx,cl // shift back again
bsf edx,edx // find first 1-bit
jnz @A200 // found
// Main loop, search 16 bytes at a time
@A100: add eax,10H // increment pointer by 16
movdqa xmm1,[eax] // read 16 bytes aligned
pcmpeqb xmm1,xmm0 // compare 16 bytes with zero
pmovmskb edx,xmm1 // get one bit for each byte result
bsf edx,edx // find first 1-bit
// (moving the bsf out of the loop and using test here would be faster
// for long strings on old processors, but we are assuming that most
// strings are short, and newer processors have higher priority)
jz @A100 // loop if not found
@A200: // Zero-byte found. Compute string length
pop ecx // restore start address
sub eax,ecx // subtract start address
add eax,edx // add byte index
@null:
end;
function StrLen(S: PAnsiChar): integer;
asm // warning: may read up to 15 bytes beyond the string itself
or eax,eax
mov edx,eax // copy pointer
jz @null // returns 0 if S=nil
xor eax,eax
pxor xmm0,xmm0
{$ifdef HASAESNI}
pcmpistri xmm0,dqword [edx],EQUAL_EACH // comparison result in ecx
{$else}
db $66,$0F,$3A,$63,$02,EQUAL_EACH
{$endif}
jnz @loop
mov eax,ecx
@null: ret
@loop: add eax,16
{$ifdef HASAESNI}
pcmpistri xmm0,dqword [edx+eax],EQUAL_EACH // comparison result in ecx
{$else}
db $66,$0F,$3A,$63,$04,$10,EQUAL_EACH
{$endif}
jnz @loop
@ok: add eax,ecx
end;
SSE2优化版本:
function StrLen(S: PAnsiChar): integer;
// pure x86 function (if SSE2 not available) - faster than SysUtils' version
asm
test eax,eax
jz @@z
cmp byte ptr [eax+0],0; je @@0
cmp byte ptr [eax+1],0; je @@1
cmp byte ptr [eax+2],0; je @@2
cmp byte ptr [eax+3],0; je @@3
push eax
and eax,-4 { DWORD Align Reads }
@@Loop:
add eax,4
mov edx,[eax] { 4 Chars per Loop }
lea ecx,[edx-$01010101]
not edx
and edx,ecx
and edx,$80808080 { Set Byte to $80 at each #0 Position }
jz @@Loop { Loop until any #0 Found }
@@SetResult:
pop ecx
bsf edx,edx { Find First #0 Position }
shr edx,3 { Byte Offset of First #0 }
add eax,edx { Address of First #0 }
sub eax,ecx { Returns Length }
@@z: ret
@@0: xor eax,eax; ret
@@1: mov eax,1; ret
@@2: mov eax,2; ret
@@3: mov eax,3
end;
function StrLen(S: PAnsiChar): integer;
asm // from GPL strlen32.asm by Agner Fog - www.agner.org/optimize
or eax,eax
mov ecx,eax // copy pointer
jz @null // returns 0 if S=nil
push eax // save start address
pxor xmm0,xmm0 // set to zero
and ecx,0FH // lower 4 bits indicate misalignment
and eax,-10H // align pointer by 16
movdqa xmm1,[eax] // read from nearest preceding boundary
pcmpeqb xmm1,xmm0 // compare 16 bytes with zero
pmovmskb edx,xmm1 // get one bit for each byte result
shr edx,cl // shift out false bits
shl edx,cl // shift back again
bsf edx,edx // find first 1-bit
jnz @A200 // found
// Main loop, search 16 bytes at a time
@A100: add eax,10H // increment pointer by 16
movdqa xmm1,[eax] // read 16 bytes aligned
pcmpeqb xmm1,xmm0 // compare 16 bytes with zero
pmovmskb edx,xmm1 // get one bit for each byte result
bsf edx,edx // find first 1-bit
// (moving the bsf out of the loop and using test here would be faster
// for long strings on old processors, but we are assuming that most
// strings are short, and newer processors have higher priority)
jz @A100 // loop if not found
@A200: // Zero-byte found. Compute string length
pop ecx // restore start address
sub eax,ecx // subtract start address
add eax,edx // add byte index
@null:
end;
function StrLen(S: PAnsiChar): integer;
asm // warning: may read up to 15 bytes beyond the string itself
or eax,eax
mov edx,eax // copy pointer
jz @null // returns 0 if S=nil
xor eax,eax
pxor xmm0,xmm0
{$ifdef HASAESNI}
pcmpistri xmm0,dqword [edx],EQUAL_EACH // comparison result in ecx
{$else}
db $66,$0F,$3A,$63,$02,EQUAL_EACH
{$endif}
jnz @loop
mov eax,ecx
@null: ret
@loop: add eax,16
{$ifdef HASAESNI}
pcmpistri xmm0,dqword [edx+eax],EQUAL_EACH // comparison result in ecx
{$else}
db $66,$0F,$3A,$63,$04,$10,EQUAL_EACH
{$endif}
jnz @loop
@ok: add eax,ecx
end;
甚至是SSE4.2优化版本:
function StrLen(S: PAnsiChar): integer;
// pure x86 function (if SSE2 not available) - faster than SysUtils' version
asm
test eax,eax
jz @@z
cmp byte ptr [eax+0],0; je @@0
cmp byte ptr [eax+1],0; je @@1
cmp byte ptr [eax+2],0; je @@2
cmp byte ptr [eax+3],0; je @@3
push eax
and eax,-4 { DWORD Align Reads }
@@Loop:
add eax,4
mov edx,[eax] { 4 Chars per Loop }
lea ecx,[edx-$01010101]
not edx
and edx,ecx
and edx,$80808080 { Set Byte to $80 at each #0 Position }
jz @@Loop { Loop until any #0 Found }
@@SetResult:
pop ecx
bsf edx,edx { Find First #0 Position }
shr edx,3 { Byte Offset of First #0 }
add eax,edx { Address of First #0 }
sub eax,ecx { Returns Length }
@@z: ret
@@0: xor eax,eax; ret
@@1: mov eax,1; ret
@@2: mov eax,2; ret
@@3: mov eax,3
end;
function StrLen(S: PAnsiChar): integer;
asm // from GPL strlen32.asm by Agner Fog - www.agner.org/optimize
or eax,eax
mov ecx,eax // copy pointer
jz @null // returns 0 if S=nil
push eax // save start address
pxor xmm0,xmm0 // set to zero
and ecx,0FH // lower 4 bits indicate misalignment
and eax,-10H // align pointer by 16
movdqa xmm1,[eax] // read from nearest preceding boundary
pcmpeqb xmm1,xmm0 // compare 16 bytes with zero
pmovmskb edx,xmm1 // get one bit for each byte result
shr edx,cl // shift out false bits
shl edx,cl // shift back again
bsf edx,edx // find first 1-bit
jnz @A200 // found
// Main loop, search 16 bytes at a time
@A100: add eax,10H // increment pointer by 16
movdqa xmm1,[eax] // read 16 bytes aligned
pcmpeqb xmm1,xmm0 // compare 16 bytes with zero
pmovmskb edx,xmm1 // get one bit for each byte result
bsf edx,edx // find first 1-bit
// (moving the bsf out of the loop and using test here would be faster
// for long strings on old processors, but we are assuming that most
// strings are short, and newer processors have higher priority)
jz @A100 // loop if not found
@A200: // Zero-byte found. Compute string length
pop ecx // restore start address
sub eax,ecx // subtract start address
add eax,edx // add byte index
@null:
end;
function StrLen(S: PAnsiChar): integer;
asm // warning: may read up to 15 bytes beyond the string itself
or eax,eax
mov edx,eax // copy pointer
jz @null // returns 0 if S=nil
xor eax,eax
pxor xmm0,xmm0
{$ifdef HASAESNI}
pcmpistri xmm0,dqword [edx],EQUAL_EACH // comparison result in ecx
{$else}
db $66,$0F,$3A,$63,$02,EQUAL_EACH
{$endif}
jnz @loop
mov eax,ecx
@null: ret
@loop: add eax,16
{$ifdef HASAESNI}
pcmpistri xmm0,dqword [edx+eax],EQUAL_EACH // comparison result in ecx
{$else}
db $66,$0F,$3A,$63,$04,$10,EQUAL_EACH
{$endif}
jnz @loop
@ok: add eax,ecx
end;
您将在我们非常优化的版本中找到所有这些函数,包括Win64版本,这几乎是我们所有开放源代码项目所共享的。我的两个解决方案可以获得两种类型字符串的长度,
至于说彼得·科尔德斯并不是都有用。
只有“PAnsiCharLen()”可以作为替代解决方案,
但速度不如Amaud Bouchez的StrLen()优化,
它比我的快三倍
2017年10月14日(mm/dd/yyy):增加了一项新功能(Clean_Str)
然而,就目前而言,我建议对两者进行三个小的修正
其中(Peter Cordes建议的两个:1)使用MovZX而不是Mov&&;
2) 使用SetZ/SetE代替LAHF/ShL,使用XOr EAX、EAX代替XOr AL、AL);
将来我可以在汇编中定义函数(现在它们是在Pascal中定义的):
旧(不完整)答案:
Delphi库中没有的一些新字符串函数可能是:
Type整型=字符集;
过程AsmKeepField(PStrIn,PStrOut:指针;FieldPos:字节;
全部:布尔型);
{给定的“字段”是不包含空格的字符序列
或制表符(#32,#9),它接受FieldPos(1..N)字段
复制到PStrIn^(字符串)并将其复制到PStrOut^(字符串)。
如果All=TRUE,则它还接受所有后续字段}
函数AsmUpCComp(PStr1,PStr2:指针):布尔值;
{比较字符串PStr1^(字符串)和字符串PStr2^(字符串),
考虑到PStr1字母字符^always SHIFT}
函数UpCaseStrComp(Str1,Str2:String;Mode:Boolean):ShortInt;
{如果Str1Str2。
MODE=FALSE表示“区分大小写比较”(字母为
想想他们的本来面目。
MODE=TRUE表示通过考虑
两个字符串都是大写的}
函数KeepLS(Str:String;CntX:Byte):String;
{返回STR中包含第一个字符的部分
包括STR和CntX位置(0到N-1)的所有后续行动}
函数KeepRS(Str:String;CntX,CsMode:Byte):String;
{返回