2016-10-11 44 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