回 帖 发 新 帖 刷新版面

主题:【求助】DELPHI 内联asm 压入字符串问题?

DELPHI 内联asm 压入字符串问题?

以前我没太注意,今天一个朋友问我DELPHI压入字符串,我随手给它编了一段代码:

var
  Form1: TForm1;
  dz01:string[100];
implementation


procedure acc;stdcall;                    
begin
dz01:= 'acc ';
asm
        pushad
        mov  ebx,$754ea4
        mov  ecx,dword ptr ds:[ebx]
        push offset dz01
        mov  ebx,$430FD0
        call ebx
        popad
end;
end;

下面是以上DELPHI代码反汇编结果
0044E7BC   60                     pusha
0044E7BD   BBA44E7500             mov     ebx, $00754EA4
0044E7C2   3E8B0B                 mov     ecx, ds:[ebx]
0044E7C5   682C044500             push    $0045042C
0044E7CA   BBD00F4300             mov     ebx, $00430FD0
0044E7CF   FFD3                   call    ebx
0044E7D1   61                     popa
0044E7D2   C3                     ret

而达不到ASM的偏移指针(压入字符串)的效果
DELPHI  效果:0044E7C5   682C044500             push    $0045042C
要达到的效果:0044E7C5   682C044500             push offset dz01

DELPHI有不有办法达到这个效果?

回复列表 (共9个回复)

沙发

这个问题困扰了我2天了,请朋友帮忙回答一下。

板凳

DELPHI  效果:0044E7C5   682C044500             push    $0045042C
要达到的效果:0044E7C5   682C044500             push offset dz01

看到最后,请问楼主的意图是要实现Delphi反汇编代码显示push offset dz01这句吗?
这是不现实的。dz01是一个全局变量,Delphi编译器在编译后,这个变量名字不复存在,只是用全局数据区的一个地址值而已。假设dz01是一个局部变量,它的名字也不会出现在反汇编代码里的,只可能使用栈偏移字节数来表示。
Delphi是编译执行的,不是解释执行的。


3 楼

指向字符串。

象这样的:
push offset dz01;"acc"

反编译出来就是这个效果。

4 楼

发现DELPHI压入字符串咋这么难。。。

5 楼

呵呵,楼主啊,你的汇编功底肯定比我深,在此我想请问:

您是要解决用Delphi实现您所说的“压入字符串”呢?还是要实现反汇编代码不显示地址立即数,而是显示“push offset dz01”这句?如果您的目的是后者,我想前面我描述得已经够清楚了。如果您的目的是前者,那么按照我的理解,push offset dz01只是把字符串变量dz01的地址入栈,而不是把字符串的每个字符入栈。

        pushad
        mov  ebx,$754ea4 ////这个立即数,我们不知是什么
        mov  ecx,dword ptr ds:[ebx]
        push offset dz01 //dz01地址入栈
        mov  ebx,$430FD0//这个立即数,我们不知是什么
        call ebx
          ////////出栈操作呢?如果没有刚才push offset dz01这个入栈操作的相应出栈操作,下面的出栈会正确吗?会不会差错4个字节?
        popad

6 楼

“push offset dz01只是把字符串变量dz01的地址入栈,而不是把字符串的每个字符入栈。”

而dz01:='acc'; 只是变量dz01地址入栈,不是字符串每个字符入栈是什么意思?
acc不能入栈吗?

7 楼

[quote]“push offset dz01只是把字符串变量dz01的地址入栈,而不是把字符串的每个字符入栈。”

而dz01:='acc'; 只是变量dz01地址入栈,不是字符串每个字符入栈是什么意思?
acc不能入栈吗?[/quote]

这说明楼主你对offset的基本理解就是错的。或者说你不了解Delphi字符串的引用计数机制(网上查一下相关资料)。对于dz01来说,它就是一个占有4字节内存空间的指针而已。

以下代码只是向你展示offset是在取址。(同时演示了lea取址)

var
  Str : string[4] = 'abc'#0;

procedure TForm1.Button1Click(Sender: TObject);
var
  P1, P2 : Pointer; //声明两个指针变量
begin
  Showmessage(Format('%p', [@Str[1]])); //字符串Str第一个字符的地址
  asm
    mov eax, offset Str[1]  //用Offset取址放入eax
    mov P1, eax             //eax寄存器值传入P1所在的四个字节
    lea eax, Str[1]         //用Lea取址放入eax
    mov P2, eax             //eax寄存器值传入P2所在的四个字节
  end;
  Showmessage(Format('%p', [P1])); //看一下P1的值,是否与@Str[1]相同
  Showmessage(Format('%p', [P2])); //看一下P2的值,是否与@Str[1]相同
  Showmessage(Char(P1^)+Char(Pointer(integer(P1)+1)^));//'ab' 注意有^号
end;

一定要注意最后一句^号的应用,这更加证明了,offset和lea取到的都是地址。

8 楼

字符串的每个字符、字符串变量的地址、都是可以压栈的。只不过看你的实际需要或遵循的使用习惯了。
楼主如果有兴趣,可以运行以下代码试试:

var
  Str : string[10] = 'abc1234de'#0;

function Test(P : PChar): integer;stdcall;
                                 //~~~~~~~~~~~
begin
  Showmessage(StrPas(P));
  Result := Length(StrPas(P));
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  R : integer;
  F : function(P: PChar):integer;
begin
  F := @Test;
  asm
    push offset Str     //参数压栈  或 push offset Str[1]
    call F              //执行函数
    mov R, eax          //获得函数返回值
    //此处不必出栈操作,因Test过程的最后已自动由Delphi给加了修复栈顶的返回语句
  end;
  Showmessage(InttoStr(R)); //返回值
end;

9 楼

11814691(delphi编程学习交流-学习者晋级者交流群) 
11815242(delphi行业软件交流-只加做行业软件的程序员高手) 
欢迎各位高手加入,请加入适合自己的群

我来回复

您尚未登录,请登录后再回复。点此登录或注册