Optimization 在汇编程序中添加两个32位整数,以便在VB6中使用

Optimization 在汇编程序中添加两个32位整数,以便在VB6中使用,optimization,assembly,vb6,add,Optimization,Assembly,Vb6,Add,我想在assembler(assembly?)中为Windows机器提供字节码,以添加两个32位长,并丢弃进位。我意识到“Windows机器”部分有点模糊,但我假设ADD的字节在所有现代英特尔指令集中几乎相同 我只是想稍微滥用VB,让一些事情变得更快。因此,作为在VB中运行直接汇编的一个示例,十六进制字符串“8A4C240833C0F6C1E075068B44240D3E0C20800”是SHL的汇编代码,可以用于快速SHL操作,需要两个长参数(我们在这里忽略VB6中的32位长参数是有符号的,只

我想在assembler(assembly?)中为Windows机器提供字节码,以添加两个32位长,并丢弃进位。我意识到“Windows机器”部分有点模糊,但我假设
ADD
的字节在所有现代英特尔指令集中几乎相同

我只是想稍微滥用VB,让一些事情变得更快。因此,作为在VB中运行直接汇编的一个示例,十六进制字符串“8A4C240833C0F6C1E075068B44240D3E0C20800”是
SHL
的汇编代码,可以用于快速
SHL
操作,需要两个长参数(我们在这里忽略VB6中的32位长参数是有符号的,只要假设它们是无符号的)

在这些相同的行中,代表汇编指令的十六进制字节字符串是什么,它们将执行相同的操作来返回两个32位无符号整数的和

根据作者的说法,上述SHL的十六进制代码是:

mov eax, [esp+4]
mov cl, [esp+8]
shl eax, cl
ret 8
我将这些字节放入一个文件中,并尝试在windows命令提示符下使用旧的调试实用程序将它们解组,但我发现它不能与较新的指令集一起工作,因为当我尝试组装某些东西时,它不喜欢
EAX
,但它对
AX
感到满意

我从源代码中的注释中知道
SHL EAX,CL
D3E0
,但是我没有任何参考资料来知道指令
ADD EAX,CL
的字节是什么,或者我想试试。(虽然我现在知道操作数必须是相同的大小。)


我试过了,但没有得到任何我能弄明白如何使用的东西。我用它来组装原始的
SHL
代码,得到了一个非常不同的结果,而不是相同的字节。帮助?

我反汇编了您提供的字节,得到了以下代码:

(__TEXT,__text) section
f:
00000000    movb    0x08(%esp),%cl
00000004    xorl    %eax,%eax
00000006    testb   $0xe0,%cl
00000009    jne     0x00000011
0000000b    movl    0x04(%esp),%eax
0000000f    shll    %cl,%eax
00000011    retl    $0x0008
这肯定比作者提供的源代码更复杂。它检查第二个操作数是否太大,例如,它根本不在您显示的代码中(有关更完整的分析,请参阅下面的编辑2)。下面是一个简单的
stdcall
函数,它将两个参数相加并返回结果:

mov  4(%esp), %eax
add  8(%esp), %eax
ret  $8
集合,它为我提供了以下输出:

(__TEXT,__text) section
00000000 8b 44 24 04 03 44 24 08 c2 08 00 
我希望这些字节能满足您的要求

编辑:也许更有用,我只是在C中做了同样的事情:

__attribute__((__stdcall__))
int f(int a, int b) 
{
  return a + b;
}
使用
-Oz
-fomit帧指针编译,它生成完全相同的代码(不管怎样,功能相当):

机器代码输出:

$ otool -t example.o
example.o:
(__TEXT,__text) section
00000000 8b 44 24 08 03 44 24 04 c2 08 00 
当然比手工编写汇编代码要好

编辑2:

@ErikE在下面的评论中询问,如果尝试32位或更大的移位,会发生什么情况。此答案顶部的反汇编代码(针对原始问题中提供的字节)可以由以下更高级别的代码表示:

unsigned int shift_left(unsigned int a, unsigned char b)
{
    if (b > 32)
        return 0;
    else
        return a << b;
}
无符号整数左移(无符号整数a,无符号字符b)
{
如果(b>32)
返回0;
其他的

返回一个看起来很棒的。谢谢你帮我解决了我的无知。你有推荐的汇编程序/反汇编程序吗?希望是免费的?或者微软有吗?还有,如果你尝试SHL超过32,比如说一些非常大的数字,会发生什么?我只是在我的Mac上使用了gcc/otool。它们是免费的。如果你需要使用windows,cygwin有免费的工具,你可以使用se.Microsoft肯定也有工具,但我不知道它们是否免费,也不知道在哪里可以买到。@Emtucifor,我将编辑我的答案,以解决您关于移位超过32位的问题。这就是我认为正在发生的事情,对32位及以上进行优化。但是shl指令对>=32的情况不会返回0吗?我搜索了testb指令,但无法找出值224如何执行32的测试任务,除非它是某种
255-n
掩码或涉及反向位顺序或其他内容。@Emtucifor,是的-指令集手册说“计数操作数可以是立即数或CL寄存器。计数被屏蔽为5位…”这确实使原始代码中的检查看起来是不必要的。十六进制中的值224是0xe0-设置了位5、6和7。设置了其中一个位的任何数字都大于32-2^5=32。添加两个32位长字符并丢弃进位-这将是
lea eax,[ecx+edx]
/
ret
如果我们谈论的是快速调用,否则
mov
load/memory source
add
/
ret
(进位标志不是返回值的一部分)。您完全把这件事复杂化了,我想知道为什么在VB源代码中调用asm函数要比使用
+
快。此外,
添加eax,cl
是不可编码的,因为操作数大小不同。另外,我觉得VB向机器代码函数传递参数的开销不太可能低于调用它自己的
+
实现。这不仅仅是对固定宽度的整数类型进行包装运算吗?二进制加法对2的补码和对无符号的补码的运算是相同的,因此如果VB6没有无符号类型,IDK将如何以一种有用的方式将此asm的结果返回到VB中。VB
+
是否扩展整数如果是这样的话,asm当然可以通过截断结果来加快速度。此外,如果您有一个连续的项数组要相加,在asm中执行整个循环应该快得多。您甚至可以使用SSE2
padd xmm0,[edx]
一次执行4个加法(SIMD),具有2/时钟负载和添加吞吐量。如果不是,则为每个添加进行函数调用很糟糕,但仍然可能比您可以让VB单独执行的任何操作都要糟糕,IDK。自从我使用VB做任何事情以来,已经有很多年了。(其中大部分是用C编写本机函数,我可以从excel中的VB调用它来做一些数据拟合,比如比本机VB代码快60倍,用于20年前的暑期学生工作。)你是否区分了
unsigned int shift_left(unsigned int a, unsigned char b)
{
    if (b > 32)
        return 0;
    else
        return a << b;
}