主题:【求助】DELPHI 内联asm 压入字符串问题?
xie139
[专家分:0] 发布于 2007-10-15 11:00:00
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个回复)
沙发
xie139 [专家分:0] 发布于 2007-10-15 11:06:00
这个问题困扰了我2天了,请朋友帮忙回答一下。
板凳
长尾兔 [专家分:3630] 发布于 2007-10-17 09:53:00
DELPHI 效果:0044E7C5 682C044500 push $0045042C
要达到的效果:0044E7C5 682C044500 push offset dz01
看到最后,请问楼主的意图是要实现Delphi反汇编代码显示push offset dz01这句吗?
这是不现实的。dz01是一个全局变量,Delphi编译器在编译后,这个变量名字不复存在,只是用全局数据区的一个地址值而已。假设dz01是一个局部变量,它的名字也不会出现在反汇编代码里的,只可能使用栈偏移字节数来表示。
Delphi是编译执行的,不是解释执行的。
3 楼
xie139 [专家分:0] 发布于 2007-10-19 00:03:00
指向字符串。
象这样的:
push offset dz01;"acc"
反编译出来就是这个效果。
4 楼
xie139 [专家分:0] 发布于 2007-10-19 00:05:00
发现DELPHI压入字符串咋这么难。。。
5 楼
长尾兔 [专家分:3630] 发布于 2007-10-19 11:01:00
呵呵,楼主啊,你的汇编功底肯定比我深,在此我想请问:
您是要解决用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 楼
xie139 [专家分:0] 发布于 2007-10-20 20:22:00
“push offset dz01只是把字符串变量dz01的地址入栈,而不是把字符串的每个字符入栈。”
而dz01:='acc'; 只是变量dz01地址入栈,不是字符串每个字符入栈是什么意思?
acc不能入栈吗?
7 楼
长尾兔 [专家分:3630] 发布于 2007-10-22 11:03:00
[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 楼
长尾兔 [专家分:3630] 发布于 2007-10-22 13:05:00
字符串的每个字符、字符串变量的地址、都是可以压栈的。只不过看你的实际需要或遵循的使用习惯了。
楼主如果有兴趣,可以运行以下代码试试:
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 楼
leiaibaixue [专家分:0] 发布于 2007-10-29 14:14:00
11814691(delphi编程学习交流-学习者晋级者交流群)
11815242(delphi行业软件交流-只加做行业软件的程序员高手)
欢迎各位高手加入,请加入适合自己的群
我来回复