C指針原理(9)

轉自: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

內存的常用分配方式有:

第一,靜態分配,所有名字在編譯時綁定某個存儲位置。不能在運行時改變 
第二,棧分配,活動時壓入系統棧。 
第三,堆分配,以任意次序分配



發佈了15 篇原創文章 · 獲贊 22 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章