源代码
#include<stdio.h>
#include<string.h>
int main() {
char szBuffer[20] = "hello world";
scanf("%s", &szBuffer);
int len = strlen(szBuffer);
printf("length=%d ", len);
return 0;
}
反汇编代码
release版本中strlen函数直接内嵌在代码块中,所以有必要了解一下strlen函数的实现,这里针对vs2019编译的结果进行分析。
0x004010B1 处很巧妙,使用了流水线优化,按理说初始化数组的指令应该在push eax之前,但是这里将它放在了push eax之后,是由于指令相关性,CPU读取xorps xmm0,xmm0时,使用了xmm0,若后面紧跟着movq qword ptr[XX],xmm0,也使用了xmm0,预读取该条指令会因为上一条指令改变xmm0的值而使预读取失效,流水线冲洗发生,为了避免这种情况,使用了流水线优化,将其放在push eax指令后面。
解读strlen
可以看到,strlen实现时 是将字符串第二个字符的地址存储在edx中(.text 004010C1),字符串中以字节为单位,每次循环传送一个字符给cl,判断cl是否为0决定是否继续循环,cl=0表示读取到字符串结尾。循环结束时,eax指向字符串结尾符‘\0’的下一位,这是eax-edx=字符串长度。
例:szBuffer=“hello”,edx存储’e’的地址,设为1,循环结束后,eax存储’\0’后一位地址,即6,6-1即hello的长度。