轉自:http://blog.csdn.net/myhaspl/article/details/14224755
我們使用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
在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
.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
內存的常用分配方式有:
第一,靜態分配,所有名字在編譯時綁定某個存儲位置。不能在運行時改變
第二,棧分配,活動時壓入系統棧。
第三,堆分配,以任意次序分配