我们使用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先存储在一个寄存器。
首先,我们看一下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
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp#分配32字节栈空间,根据变量情况分配
movl $.LC0, 24(%esp)#x变量使用指针(4个字节大小),放入栈中,可以看到,变量分配靠近栈空间的尾部
movw $31097, 29(%esp)#字符'yy'移到main程序的栈中,直接将y变量的值放入栈中
movb $0, 31(%esp)#加上NULL标志,表示字符结束
movl $.LC1, %eax
leal 29(%esp), %edx
movl %edx, 8(%esp)
movl 24(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
movl $0, (%esp)
call exit
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
#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
.type myprinf, @function
myprinf:
pushl %ebp
movl %esp, %ebp
subl $40, %esp
movl $.LC0, -16(%ebp)
movw $31097, -11(%ebp)
movb $0, -9(%ebp)
movl $.LC1, %eax
leal -11(%ebp), %edx
movl %edx, 8(%esp)
movl -16(%ebp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
leave
ret
.size myprinf, .-myprinf
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $1, 28(%esp)
call myprint
movl $0, (%esp)
call exit
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
内存的常用分配方式有:
第一,静态分配,所有名字在编译时绑定某个存储位置。不能在运行时改变
第二,栈分配,活动时压入系统栈。
第三,堆分配,以任意次序分配
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。