1. 程式人生 > >C指針原理(9)-C內嵌匯編

C指針原理(9)-C內嵌匯編

-s 包含 bit 編譯 volatile 符號表 其他 ret 一個

我們使用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

內存的常用分配方式有:

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

C指針原理(9)-C內嵌匯編