我们使用 m 标记可以直接在内存中对数进行操作, 前面的例子对变量进行操作时都需要将变量值存储在要修改的寄存器中, 然后将它写回内存位置中.
- #include
- 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
- 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
在 MAIN 函数中 char * 分配在只读数据段中, 实际使用时, 只在程序栈中分配一个指针的空间. char[] 在程序栈中分配空间, 然后直接使用 movl,movw 之类的汇编直接把值放入栈中空间. 那么在其它函数中声明的呢, 可以从以下程序中看出, 仍然如此.
- #include
- 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
内存的常用分配方式有:
第一, 静态分配, 所有名字在编译时绑定某个存储位置. 不能在运行时改变?
第二, 栈分配, 活动时压入系统栈.?
第三, 堆分配, 以任意次序分配
来源: http://www.bubuko.com/infodetail-2867502.html