Function Delphi-编写一个带有函数的.pas库

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

我正在用汇编语言在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
    jne @here
    dec ecx
    mov Result,ecx
  end;
end;

它计算字符串中的字符数。如何在lib
Strings中创建它。使用
调用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;
{返回