使用匯編分析c代碼的內存分布
arm平台下使用反匯編分析c內存分布:
arm:使用arm-linux-objdump命令將編譯完成之後的elf文件,進行反匯編.
之後重定向到tmp.s文件中.
第一步變量如下c文件.
vim tmp.c
#include
#define VAR 0xFF
int a = 0;
static int b = 0;
int c = 10;
static int d = 20;
const int finalone = 10;
const int final;
int main(void)
{
char *hell = "hhhhhhh";
const int finaltwo = 50 ;
static int f = 0;
static int k = 10;
int aa;
int bb=10;
printf("VAR = %d\n, finalone = %d, finaltwo = %d",VAR,finalone,finaltwo);
}
第二步:編寫Makefile文件如下
Makefile文件如下:
vim Makefile
CC=arm-linux-gcc
CFLAGS += -march=armv7-a
第三步:編譯生成可執行文件.
然後使用make命令編譯給文件.make tmp 生成tmp elf格式文件.
第四步:
下面通過使用arm-linux-objdump -D tmp > tmp.s
//得到如下文件tmp.s文件.
: file format elf32-littlearm
下面是摘出來的相關內如如下:
//下面是對應的.data段相關的初始化的變量.
//變量c,d,k都存取再該區域內.結論如下:
//需要滿足如下要求的變量被放在.data段,也就是初始化數據段.
//所有全局||static關鍵字修飾)&&初始化不為的變量)
sassembly of section .data:
00011020 <__data_start>:
11020: 00000000 andeq r0, r0, r0
00011024 <__dso_handle>:
11024: 00000000 andeq r0, r0, r0
00011028 :
11028: 0000000a andeq r0, r0, sl
0001102c :
1102c: 00000014 andeq r0, r0, r4, lsl r0
00011030 :
11030: 0000000a andeq r0, r0, sl
//下面是對應的.bss段.變量a,b,f都存儲再這個區域.
//該區域存儲的是沒有初始化或者初始化為0的變量.
這些變量應該滿足如下,條件才會被放到給區域:
(全局的|被static關鍵字修飾的)&&(為初始化||初始化為0的變量)
Disassembly of section .bss:
00011034 :
11034: 00000000 andeq r0, r0, r0
00011038 :
11038: 00000000 andeq r0, r0, r0
0001103c :
1103c: 00000000 andeq r0, r0, r0
00011040 :
11040: 00000000 andeq r0, r0, r0
00011044 :
11044: 00000000 andeq r0, r0, r0
//這個區域存放了一些字符串常量.如上c程序中的 "hhhhhhh"對應的686868.....
//還有使用const修飾的全局初始化的常量.如上面的const int finalone變量.它的只對應的是848c的00000000a.
sassembly of section .rodata:
00008488 <_IO_stdin_used>:
8488: 00020001 andeq r0, r2, r1
0000848c :
848c: 0000000a andeq r0, r0, sl
8490: 68686868 stmdavs r8!, {r3, r5, r6, fp, sp, lr}^
8494: 68686868 stmdavs r8!, {r3, r5, r6, fp, sp, lr}^
8498: 00000068 andeq r0, r0, r8, rrx
849c: 20524156 subscs r4, r2, r6, asr r1
84a0: 6425203d strtvs r2, [r5], #-61 ; 0x3d
84a4: 66202c0a strtvs r2, [r0], -sl, lsl #24
84a8: 6c616e69 stclvs 14, cr6, [r1], #-420 ; 0xfffffe5c
84ac: 20656e6f rsbcs r6, r5, pc, ror #28
84b0: 6425203d strtvs r2, [r5], #-61 ; 0x3d
84b4: 6966202c stmdbvs r6!, {r2, r3, r5, sp}^
84b8: 746c616e strbtvc r6, [ip], #-366 ; 0x16e
84bc: 3d206f77 stccc 15, cr6, [r0, #-476]! ; 0xfffffe24
84c0: 2c642520 cfstr64cs mvdx2, [r4], #-128 ; 0xffffff80
84c4: 203d2068 eorscs r2, sp, r8, rrx
84c8: 00732520 rsbseq r2, r3, r0, lsr #10}
//上面還使用#define聲明一個宏.它存儲再哪裡呢.我們可以看一下啊main中的匯編如下:
//第一步找出.在main中聲明的局部變量.
char *hell = "hhhhhhh" //這個是hell變量的聲明,83c0: e3083490 movw r3, #33936 ; 0x8490
const int finaltwo = 50 ; // 83cc: e3a03032 mov r3, #50 ; 0x32 //它會被保存的棧中.
static int f = 0;
static int k = 10;
int aa; //aa變量被默認優化,不存在了.因為沒有被使用,也沒有使用volatile關鍵字修飾,
//編譯在當前arm平台下默認優化等級是O2,那麼將將會再匯編中步存在.
int bb=10; //83d4: e3a0300a mov r3, #10 這個是bb=10
//這段匯編代碼中還包含一個#255,也就是我們使用#define VAR 255 常量,
//它是一個立即數.說明它只占用.text文本段,也就是我們常說的代碼段.
//下面由段詳細的解釋:說明const,和#define常量的不同之處.
000083b4 :
83b4: e92d4800 push {fp, lr}
83b8: e28db004 add fp, sp, #4
83bc: e24dd018 sub sp, sp, #24
83c0: e3083490 movw r3, #33936 ; 0x8490
83c4: e3403000 movt r3, #0
83c8: e50b3008 str r3, [fp, #-8]
83cc: e3a03032 mov r3, #50 ; 0x32
83d0: e50b300c str r3, [fp, #-12]
83d4: e3a0300a mov r3, #10
83d8: e50b3010 str r3, [fp, #-16]
83dc: e308349c movw r3, #33948 ; 0x849c
83e0: e3403000 movt r3, #0
83e4: e308248c movw r2, #33932 ; 0x848c
83e8: e3402000 movt r2, #0
83ec: e5922000 ldr r2, [r2]
83f0: e51b1008 ldr r1, [fp, #-8]
83f4: e58d1000 str r1, [sp]
83f8: e1a00003 mov r0, r3
83fc: e3a010ff mov r1, #255 ; 0xff
8400: e51b300c ldr r3, [fp, #-12]
8404: ebffffbc bl 82fc <_init+0x44>
8408: e1a00003 mov r0, r3
840c: e24bd004 sub sp, fp, #4
8410: e8bd8800 pop {fp, pc}
//解析define和const的不同之處.
const 定義的只讀變量從匯編角度來看 只是給出了對應的內存地址
而不是像define一樣給出的是立即數 所以 const定義的只讀變量在程序運行過程中只有一份拷貝
(因為它是全局的只讀變量 存放在靜態區) 而define定義的宏變量在內存中有若干個拷貝 define宏是在預編譯階段進行替換
而const修飾的只讀變量是在編譯的時候確定其值 define宏沒有類型 而const修飾的只讀變量具有特定的類型.