C指针原理(9)-C内嵌汇编

来源:互联网 发布:nginx cookie 灰度 编辑:程序博客网 时间:2024/05/21 04:43

我们使用m标记可以直接在内存中对数进行操作,前面的例子对变量进行操作时都需要将变量值存储在要修改的寄存器中,然后将它写回内存位置中.



#include <stdio.h>int main(void){    int xa=2;    int xb=6;     asm volatile(    "subl %1,%0\n\t"      :"=r"(xb):"m"(xa),"0"(xb));        printf("%d\n",xb);    return 0;}

我们直接从xa的内存地址中将xa取出,而不需要再将xa先存储在一个寄存器。

本博客所有内容是原创,如果转载请注明来源

http://blog.csdn.net/myhaspl/


首先,我们看一下AT&T汇编各段的意义

 

 

含义.text已编译程序的机器代码.rodata只读数据,如pintf和switch语句中的字符串和常量值.data已初始化的全局变量.bss未初始化的全局变量.symtab符号表,存放在程序中被定义和引用的函数和全局变量的信息.rel.text当链接器吧这个目标文件和其他文件结合时,.text节中的信息需修改.rel.data被模块定义和引用的任何全局变量的信息.debug一个调试符号表。.line原始C程序的行号和.text节中机器指令之间的映射.strtab一个字符串表,其内容包含.systab和.debug节中的符号表

 

上面列表也许比较抽象,我们从一个C程序生成的中间汇编代码分析:


#include <stdio.h>void main(){   char *x="xxxx";   char y[]="yy";//y的16进制ASCII码是97,9797的十进制为31097   printf("%s-----%s",x,y);   exit(0);}


 我们使用gcc -S testcr.c,查看编译生成的汇编代码(为便于理解,将生成的汇编代码进行了注释)

.file"testcr.c".section.rodata.LC0:.string"xxxx"#使用char *分配.LC1:.string"%s-----%s".text.globl main.typemain, @functionmain:pushl%ebpmovl%esp, %ebpandl$-16, %espsubl$32, %esp#分配32字节栈空间,根据变量情况分配movl$.LC0, 24(%esp)#x变量使用指针(4个字节大小),放入栈中,可以看到,变量分配靠近栈空间的尾部movw$31097, 29(%esp)#字符'yy'移到main程序的栈中,直接将y变量的值放入栈中movb$0, 31(%esp)#加上NULL标志,表示字符结束 movl$.LC1, %eaxleal29(%esp), %edxmovl%edx, 8(%esp)movl24(%esp), %edxmovl%edx, 4(%esp)movl%eax, (%esp)callprintfmovl$0, (%esp)callexit.sizemain, .-main.ident"GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3".section.note.GNU-stack,"",@progbits 

在MAIN函数中char *分配在只读数据段中,实际使用时,只在程序栈中分配一个指针的空间。char[] 在程序栈中分配空间,然后直接使用movl、movw之类的汇编直接把值放入栈中空间。那么在其它函数中声明的呢,可以从以下程序中看出,仍然如此。

#include <stdio.h>void myprinf(){   char *x="xxxx";   char y[]="yy";//y的16进制ASCII码是97,9797的十进制为31097   printf("%s-----%s",x,y);}void main(){   int num=1;   myprint();   exit(0);}

生成的中间汇编代码为:

.file"testcr.c".section.rodata.LC0:.string"xxxx".LC1:.string"%s-----%s".text.globl myprinf.typemyprinf, @functionmyprinf:pushl%ebpmovl%esp, %ebpsubl$40, %espmovl$.LC0, -16(%ebp)movw$31097, -11(%ebp)movb$0, -9(%ebp)movl$.LC1, %eaxleal-11(%ebp), %edxmovl%edx, 8(%esp)movl-16(%ebp), %edxmovl%edx, 4(%esp)movl%eax, (%esp)callprintfleaveret.sizemyprinf, .-myprinf.globl main.typemain, @functionmain:pushl%ebpmovl%esp, %ebpandl$-16, %espsubl$32, %espmovl$1, 28(%esp)callmyprintmovl$0, (%esp)callexit.sizemain, .-main.ident"GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3".section.note.GNU-stack,"",@progbits

内存的常用分配方式有:

第一,静态分配,所有名字在编译时绑定某个存储位置。不能在运行时改变 
第二,栈分配,活动时压入系统栈。 
第三,堆分配,以任意次序分配