gcc 下内联汇编的一些简单案例讲解
程序员文章站
2022-06-17 22:49:06
...
具体的教程 参考转载的前一篇博文 GCC 内联汇编 https://blog.****.net/m0_37329910/article/details/89465064
持续更新中
案列
demo1
直接看代码
char dest_m[0x20] = {'\0'};
static inline char * strcpy_zj(char * dest,const char *src)
{
int d0, d1, d2;
__asm__ __volatile__( "1:\tlodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b"
: "=&S" (d0), "=&D" (d1), "=&a" (d2)
: "0" (src),"1" (dest)
: "memory");
return dest;
}
int main(){
char *src_m = "zhangji";
strcpy_zj(dest_m, src_m);
return 0;
}
编译
gcc -m32 -g demo1.c -o demo1
基本知识点
先解释下内联汇编中的 修饰约束 (第三个冒号后面)
基本格式为:
asm ( 汇编程序模板
: 输出操作数 /* 可选的 /
: 输入操作数 / 可选的 /
: 修饰寄存器列表 / 可选的 */
);
当使用约束时,对于更精确的控制超过了对约束作用的需求,GCC 给我们提供了约束修饰符。最常用的约束修饰符为:
- “=” : 意味着对于这条指令,操作数为只写的;旧值会被忽略并被输出数据所替换。
- “&” : 意味着这个操作数为一个早期改动的操作数,其在该指令完成前通过使用输入操作数被修改了。因此,这个操作数不可以位于一个被用作输出操作数或任何内存地址部分的寄存器。如果在旧值被写入之前它仅用作输入而已,一个输入操作数可以为一个早期改动操作数。
直接看汇编代码
Dump of assembler code for function strcpy_zj:
0x080483ed <+0>: push ebp
0x080483ee <+1>: mov ebp,esp
0x080483f0 <+3>: push edi
0x080483f1 <+4>: push esi
0x080483f2 <+5>: sub esp,0x10
0x080483f5 <+8>: mov edx,DWORD PTR [ebp+0xc] !!!arg2 src
0x080483f8 <+11>: mov eax,DWORD PTR [ebp+0x8] !!!arg1 dest
0x080483fb <+14>: mov ecx,edx
0x080483fd <+16>: mov edx,eax
0x080483ff <+18>: mov esi,ecx !!! esi
0x08048401 <+20>: mov edi,edx !!! edi
0x08048403 <+22>: lods al,BYTE PTR ds:[esi]
0x08048404 <+23>: stos BYTE PTR es:[edi],al
0x08048405 <+24>: test al,al
0x08048407 <+26>: jne 0x8048403 <strcpy_zj+22>
0x08048409 <+28>: mov edx,edi !!! edi
0x0804840b <+30>: mov ecx,esi !!! esi
0x0804840d <+32>: mov DWORD PTR [ebp-0x14],ecx !!! &d0 , esi
0x08048410 <+35>: mov DWORD PTR [ebp-0x10],edx !!! &d1, edi
0x08048413 <+38>: mov DWORD PTR [ebp-0xc],eax !!! &d2, eax
0x08048416 <+41>: mov eax,DWORD PTR [ebp+0x8]
=> 0x08048419 <+44>: add esp,0x10
0x0804841c <+47>: pop esi
0x0804841d <+48>: pop edi
0x0804841e <+49>: pop ebp
0x0804841f <+50>: ret
代码中 d0 d1 d2 与寄存器的关系 进行了跟踪 基本明了
推荐阅读