Assembly 在汇编程序中导出优化strlen?
下面的代码能够确定DWORD的一个或多个字节是否设置为0Assembly 在汇编程序中导出优化strlen?,assembly,Assembly,下面的代码能够确定DWORD的一个或多个字节是否设置为0 mov eax, value mov edx, 07EFEFEFFh add edx, eax xor eax, 0FFFFFFFFh xor eax, edx and eax, 081010100h 例如,如果我们输入34323331h,eax=0 然而,如果我们输入1字节设置为00的内容,比如34003231h,eax!=0 我知道这段代码是做什么的,但我不明白它是如何做到的。这在数学上是如何工作的?有人能用比特向我解释这个过程吗?
mov eax, value
mov edx, 07EFEFEFFh
add edx, eax
xor eax, 0FFFFFFFFh
xor eax, edx
and eax, 081010100h
例如,如果我们输入34323331h,eax=0
然而,如果我们输入1字节设置为00的内容,比如34003231h,eax!=0
我知道这段代码是做什么的,但我不明白它是如何做到的。这在数学上是如何工作的?有人能用比特向我解释这个过程吗?这是如何推导出来的
它应该相对简单,但我就是看不到它我将从右边的0开始计算位 简短答复: 将
11111111
添加到零字节(00000000
)时,溢出位(第8位)与值+0x7EFEFF
的相同溢出位没有差异
将11111111
添加到非零字节时,溢出位(第8位)与value+0x7EFEFEFF
的相同溢出位不同
程序只是检查这些位
长答覆:
这是代码的数学表示形式(a
是值):
在哪里
是magic
0x7EFEFEFF
表示按位异或^
表示按位和&
表示按位反转,也称为异或,与0xffffff
0x7efeff
的作用,请查看其二进制表示:
01111110 11111110 11111110 11111111
0
是神奇的溢出位。这些是第8、16、24和31位
让我们看几个例子
示例1:eax=0x00000000
当我们用异或a+magic
时!a
我们得到:
result = 10000001 00000001 00000001 00000000
result = 10000001 00000001 00000000 11111110
result = 01111001 00000000 11111100 11111110
result = 01111000 11111100 11111110 11111110
看看这些神奇的片段。它们都是1
然后,我们只需通过清除其余的位(这里都是0
),并通过100000010000000100000000
aka对结果进行运算!魔术
。如您所知,和
ing by 0仅将0分配给该位,和
ing by 1对该位不做任何操作
最终结果:
10000001 00000001 00000001 00000000
10000001 00000001 00000000 00000000
示例2:eax=0x00000001
当我们用异或a+magic
时!a
我们得到:
result = 10000001 00000001 00000001 00000000
result = 10000001 00000001 00000000 11111110
result = 01111001 00000000 11111100 11111110
result = 01111000 11111100 11111110 11111110
看看这些神奇的部分。第16、24和31位为1。第8位是0
- 第8位表示第一个字节。如果第一个字节不是零,则第8位此时变为
1
。否则它是0
- 第16位表示第二个字节。同样的逻辑
- 第24位表示第三个字节
- 第31位表示第四个字节
然后我们再次通过清除非魔法位,并用对结果进行加密!魔术
最终结果:
10000001 00000001 00000001 00000000
10000001 00000001 00000000 00000000
示例3:eax=0x34003231
当我们用异或a+magic
时!a
我们得到:
result = 10000001 00000001 00000001 00000000
result = 10000001 00000001 00000000 11111110
result = 01111001 00000000 11111100 11111110
result = 01111000 11111100 11111110 11111110
只有第24位是1
清除非魔法位后,最终结果为:
00000001 00000000 00000000 00000000
00000000 00000000 00000000 00000000 (zero)
示例4:eax=0x34323331
当我们用异或a+magic
时!a
我们得到:
result = 10000001 00000001 00000001 00000000
result = 10000001 00000001 00000000 11111110
result = 01111001 00000000 11111100 11111110
result = 01111000 11111100 11111110 11111110
清除非魔法位后,最终结果为:
00000001 00000000 00000000 00000000
00000000 00000000 00000000 00000000 (zero)
我编写了一个用于演示的测试用例:
#include <stdint.h> // uint32_t
#include <stdio.h> // printf
//assumes little endian
void printBits(size_t const size, void const * const ptr)
{
unsigned char *b = (unsigned char*) ptr;
unsigned char byte;
int i, j;
for (i = size - 1; i >= 0; i--) {
for (j = 7; j >= 0; j--) {
byte = b[i] & (1 << j);
byte >>= j;
printf("%u", byte);
}
printf(" ");
}
}
int main()
{
uint32_t a = 0;
uint32_t d = 0;
const uint32_t magic = 0x7EFEFEFF;
const uint32_t magicRev = magic ^ 0xFFFFFFFF;
const uint32_t numbers[] = {
0x00000000, 0x00000001, 0x34003231,
0x34323331, 0x01010101
};
for (int i = 0; i != sizeof(numbers) / sizeof(numbers[ 0 ]); i++) {
a = numbers[ i ];
d = magic;
printf("a: ");
printBits(sizeof(a), &a);
printf("\n");
d = a + d;
printf("a+magic: ");
printBits(sizeof(d), &d);
printf("\n");
a = a ^ 0xFFFFFFFF;
printf("!a: ");
printBits(sizeof(a), &a);
printf("\n");
a = a ^ d;
printf("result: ");
printBits(sizeof(a), &a);
printf("\n");
a = a & magicRev;
printf(" ");
printBits(sizeof(a), &a);
if (a == 0) {
printf(" (zero)\n");
} else {
printf(" (at least one)\n");
}
printf("\n");
}
return 0;
}
#包括//uint32\t
#包括//printf
//假设小端点
无效打印位(大小\u t常量大小,无效常量*常量ptr)
{
无符号字符*b=(无符号字符*)ptr;
无符号字符字节;
int i,j;
对于(i=size-1;i>=0;i--){
对于(j=7;j>=0;j--){
字节=b[i]&(1>=j;
printf(“%u”,字节);
}
printf(“”);
}
}
int main()
{
uint32_t a=0;
uint32_t d=0;
常数uint32\u t magic=0x7efeff;
常数uint32\u t magicRev=magic^0xffffff;
常数32_t编号[]={
0x00000000,0x00000001,0x34003231,
0x34323331,0x01010101
};
对于(int i=0;i!=sizeof(数字)/sizeof(数字[0]);i++){
a=数字[i];
d=魔法;
printf(“a:”);
打印位(sizeof(a),&a);
printf(“\n”);
d=a+d;
printf(“a+magic:”);
打印位(尺寸f(d)和d);
printf(“\n”);
a=a^0xFFFFFFFF;
printf(“!a:”);
打印位(sizeof(a),&a);
printf(“\n”);
a=a^d;
printf(“结果:”);
打印位(sizeof(a),&a);
printf(“\n”);
a=a&magicRev;
printf(“”);
打印位(sizeof(a),&a);
如果(a==0){
printf(“(零)\n”);
}否则{
printf(“(至少一个)\n”);
}
printf(“\n”);
}
返回0;
}
要检查值是否包含零字节,还有其他更快的方法: