2016-10-11 51 views
1

我正在寫一個mini os。當我寫這篇文章的代碼顯示實時時鐘,它不順心i386-elf-gcc輸出關於「static a = 0」的奇怪彙編指令

7 void timer_callback(pt_regs *regs) 
    8 { 
    9  static uint32_t tick = 0; 
10  printf("Tick: %dtimes\n", tick); 
11  tick++; 
12 } 

蜱是0不是初始化,但1818389861.但如果剔初始化與0×01或任何其他零,沒關係!

,所以我WIRTE一個簡單的C文件,然後objdump的:

staic.o:  file format elf32-i386 


Disassembly of section .text: 

00000000 <main>: 
extern void printf(char *, int); 

int main(){ 
    0: 8d 4c 24 04    lea 0x4(%esp),%ecx 
    4: 83 e4 f0    and $0xfffffff0,%esp 
    7: ff 71 fc    pushl -0x4(%ecx) 
    a: 55      push %ebp 
    b: 89 e5     mov %esp,%ebp 
    d: 51      push %ecx 
    e: 83 ec 04    sub $0x4,%esp 
    static int a = 1; 
    printf("%d\n", a); 
    11: a1 00 00 00 00   mov 0x0,%eax 
    16: 83 ec 08    sub $0x8,%esp 
    19: 50      push %eax 
    1a: 68 00 00 00 00   push $0x0 
    1f: e8 fc ff ff ff   call 20 <main+0x20> 
    24: 83 c4 10    add $0x10,%esp 
    return 0; 
    27: b8 00 00 00 00   mov $0x0,%eax 
} 
    2c: 8b 4d fc    mov -0x4(%ebp),%ecx 
    2f: c9      leave 
    30: 8d 61 fc    lea -0x4(%ecx),%esp 
    33: c3      ret 

這麼奇怪,使用無記憶!

更新:讓我說清楚

  1. 第二static.c文是一個實驗,有人認爲它沒有顯示使用的內存,但是我錯了,mov 0x0 %eab是。我混淆0x0和$ 0x0/.. \

  2. 我的起源問題是爲什麼剔不成功與初始值爲0.(但可以初始化1或anyelsenumber)。

  3. 我期待它再次使用gdb的,好吧,它做使用記憶像是mov
    eax,ds:0x106010
    ,但真正的強者就是內存x 0x106010不爲0,但它應該是,就像我說的,如果我讓tick = 1 or anythingelse,內存做初始化,因爲我想,這是奇怪的事情!

  4. 工具:GDB,objdump的返回不同的ASM(不同的手段,而不是甲酸鹽),因爲,剛學操作系統,位於C不好,所以我讓他走,不理它....

+0

問題是什麼嗎?你也展示了一些C代碼,但反彙編是爲了不同的東西 - 連接是什麼?你提到的奇怪裝配在哪裏? – nos

+1

如果在第一次調用timer_callback時tick不是打印爲零,那麼您的代碼中的其他位置必須有未定義的行爲。在你使用'a'的第二個例子中,因爲編譯器已經優化了它,所以沒有使用內存,它不需要是靜態的,因爲你只打印一次然後退出。 –

+1

11:處的指令是從地址0x0到%eax的一個mov。地址爲0x0的原因是因爲這是一個目標文件,鏈接程序所做的重定位尚未完成。鏈接後,這將是一個適當的地址,從一個適當的內存位置「a」存儲。 – Art

回答

3

使用內存,請確定;但是,在.text部分中找不到該內存。對於靜態變量的內存分配在.bss(零初始化時;或者在C++的情況下,動態初始化)或.data(當初始化爲非零時)部分。

使用-d(反彙編)選項轉儲具有objdump的目標文件時,重要的是還要使用-r(重定位)選項。沒有這些,你得到的反彙編是欺騙性的,沒有什麼意義。

在你的情況下,在地址111f指令必須搬遷,地址11,給變量a和地址1f,到功能printf。在地址11的指令從您的變量a值,如果沒有適當的重新定位,它看起來像從地址0

加載值至於你原來的問題,你得到的價值,1818389861,或0x6C626D65,是相當卓越。我敢打賭,在你的程序的某個地方,你有一個緩衝區溢出涉及到一個包含子序列embl的字符串。

作爲便箋,我想請您注意在printf調用中使用正確的類型規範。型號規格%d對應於int型;在所有現代主流架構中,intint32_t的大小相同。但是,這並不能保證永遠如此。有特殊類型的規格有明確大小的類型使用,例如,對於int32_t使用"PRId32"

uint32_t x; 
printf("%"PRId32, x); 
+0

優秀的,知識淵博的答案。該ASCII序列是一個很好的捕獲。但你錯過了一個地方。 '1a'也有搬遷。這裏推送的常量是格式字符串的地址。 – Art

+0

@藝術,真;我花了太多時間在地址'27'處理指令。爲什麼編譯器在這裏發出如此長的指令? – ach

+0

我得到'mov $ 0,%eax',gcc低於-O2,-O2我得到了更多預期的'xorl%eax,%eax'。我想gcc甚至不會爲沒有更高優化級別的簡單恆定負載生成良好的代碼。奇怪,但並不完全不令人驚訝。 – Art