系统启动(6)main.c

1820阅读 0评论2012-07-09 qtdszws
分类:LINUX

从现在开始,进入C代码,这部分任务使用C比用汇编语言更方便

void main(void)
{
    /* First, copy the boot header into the "zeropage" */
    copy_boot_params();

    /* Initialize the early-boot console */
    console_init();
    if (cmdline_find_option_bool("debug"))
        puts("early console in setup code\n");

    /* End of heap check */
    init_heap();

    /* Make sure we have all the proper CPU support */
    if (validate_cpu()) {
        puts("Unable to boot - please use a kernel appropriate "
             "for your CPU.\n");
        die();
    }

    /* Tell the BIOS what CPU mode we intend to run in. */
    set_bios_mode();

    /* Detect memory layout */
    detect_memory();

    /* Set keyboard repeat rate (why?) */
    keyboard_set_repeat();

    /* Query MCA information */
    query_mca();

    /* Query Intel SpeedStep (IST) information */
    query_ist();

    /* Query APM information */
#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
    query_apm_bios();
#endif

    /* Query EDD information */
#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
    query_edd();
#endif

    /* Set the video mode */
    set_video();

    /* Do the last things and invoke protected mode */
    go_to_protected_mode();
}


注意header.S中的代码是16位的,通过伪指令.code16指示
其中调用main的指令是
calll main
call后面的后缀是l,代表32位操作模式

目前gcc不支持生成16位代码,只能是32位或64位。
因此main.c编译后的指令将是32位。

我们知道,如果不考虑模式,指令的字节码都是一样的。
例如
.cdoe16
push %bp

.code32
push %ebp
经过as汇编后的字节指令都是55

在16位模式下,执行32位代码,需要加指令前缀66和67,反过来也是
指令前缀0x66可以用来选择非默认值的操作数大小;前缀0x67可用来选择非默认值的地址大小

这样,虽然gcc生成的汇编指令是32位的,但可以通过指示当前模式是16位,通知汇编器在所有的使用32位模式的指令前面增加66,67前缀,使得指令能够正确执行

我们看看main.c编译命令
  gcc -Wp,-MD,arch/x86/boot/.main.o.d  -nostdinc -isystem /usr/local/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/include -I/home/zws/linux-3.0/arch/x86/include -Iarch/x86/include/generated -Iinclude  -include include/generated/autoconf.h -D__KERNEL__ -I/home/zws/linux-3.0/arch/x86/include -Iarch/x86/include/generated -Iinclude -include include/generated/autoconf.h -g -Os -D_SETUP -D__KERNEL__ -DDISABLE_BRANCH_PROFILING -Wall -Wstrict-prototypes -march=i386 -mregparm=3 -include /home/zws/linux-3.0/arch/x86/boot/code16gcc.h -fno-strict-aliasing -fomit-frame-pointer -ffreestanding -fno-toplevel-reorder -fno-stack-protector -m32    -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(main)"  -D"KBUILD_MODNAME=KBUILD_STR(main)" -c -o arch/x86/boot/main.o arch/x86/boot/main.c

注意-include /home/zws/linux-3.0/arch/x86/boot/code16gcc.h
/*
 * code16gcc.h
 *
 * This file is -include'd when compiling 16-bit C code.
当编译16位C代码时这个文件被包含
 * Note: this asm() needs to be emitted before gcc emits any code.
在gcc发射任何指令前这个asm命令需要被发射
 * Depending on gcc version, this requires -fno-unit-at-a-time or
 * -fno-toplevel-reorder.
依赖gcc版本,需要-fno-unit-at-a-time或者-fno-toplevel-reorder选项
 *
 * Hopefully gcc will eventually have a real -m16 option so we can
 * drop this hack long term.
希望gcc能够支持-m16选项支持实模式,这样我们可以不需要长期地这样非常规实现
 */

#ifndef __ASSEMBLY__
asm(".code16gcc");
#endif

通过发射.code16gcc伪指令,指示as加前缀66和67到32位代码前,以实现16位下的32位操作

还有一个相关选项no-toplevel-reorder
       -fno-toplevel-reorder
           Do not reorder top-level functions, variables, and "asm" statements.  Output them in the same order that they appear in the input file.  When this option is used, unreferenced static variables will not be removed.  This option is intended to support existing code which relies on a particular ordering.  For new code, it is better to use attributes.
不要重组顶层函数,变量和asm语句。以他们在文件中出现的顺序输出。当这个选项被使用时,未必引用的静态变量不会被移除。这个选项用于支持现存的依赖特定顺序的代码,对于新代码,最好使用编译属性。

具备这些知识后,我们再查询main.o的汇编代码就一目了然了
[zws@ssq_pppoe boot]$ objdump -Mi8086 -d main.o

main.o:     file format elf32-i386


Disassembly of section .text.startup:

00000000
:
   0:   66 55                   push   %ebp
   2:   66 89 e5                mov    %esp,%ebp
   5:   66 57                   push   %edi
   7:   66 56                   push   %esi
   9:   66 83 e4 f0             and    $0xfffffff0,%esp
   d:   66 81 ec b0 00 00 00    sub    $0xb0,%esp
  14:   66 b8 f1 01 00 00       mov    $0x1f1,%eax
  1a:   66 be 00 00 00 00       mov    $0x0,%esi
  20:   66 b9 67 00 00 00       mov    $0x67,%ecx
  26:   66 89 c7                mov    %eax,%edi
  29:   f3 a4                   rep movsb %ds:(%si),%es:(%di)
  2b:   66 83 3e 28 02 00       cmpl   $0x0,0x228
  31:   75 2d                   jne    60
  33:   81 3e 20 00 3f a3       cmpw   $0xa33f,0x20
  39:   75 25                   jne    60
  3b:   8b 16 22 00             mov    0x22,%dx
  3f:   66 b8 00 90 ff ff       mov    $0xffff9000,%eax
  45:   3b 16 12 02             cmp    0x212,%dx
  49:   73 02                   jae    4d
  4b:   8c d8                   mov    %ds,%ax
  4d:   66 0f b7 c0             movzwl %ax,%eax
  51:   66 c1 e0 04             shl    $0x4,%eax
  55:   66 0f b7 d2             movzwl %dx,%edx
  59:   66 01 d0                add    %edx,%eax
  5c:   66 a3 28 02             mov    %eax,0x228
  60:   66 e8 fc ff ff ff       calll  62
  66:   66 ba 00 00 00 00       mov    $0x0,%edx
  6c:   66 a1 28 02             mov    0x228,%eax
  70:   66 e8 fc ff ff ff       calll  72
  76:   66 85 c0                test   %eax,%eax
  79:   74 0c                   je     87
  7b:   66 b8 06 00 00 00       mov    $0x6,%eax
  81:   66 e8 fc ff ff ff       calll  83
  87:   80 3e 11 02 00          cmpb   $0x0,0x211
  8c:   79 26                   jns    b4
  8e:   67 66 8d 84 24 00 fe    addr32 lea -0x200(%esp),%eax
  95:   ff ff
  97:   66 0f b7 16 24 02       movzwl 0x224,%edx
  9d:   66 81 c2 00 02 00 00    add    $0x200,%edx
  a4:   66 89 16 00 00          mov    %edx,0x0
  a9:   66 39 c2                cmp    %eax,%edx
  ac:   76 12                   jbe    c0
  ae:   66 a3 00 00             mov    %eax,0x0
  b2:   eb 0c                   jmp    c0
  b4:   66 b8 23 00 00 00       mov    $0x23,%eax
  ba:   66 e8 fc ff ff ff       calll  bc
  c0:   66 e8 fc ff ff ff       calll  c2
  c6:   66 85 c0                test   %eax,%eax
  c9:   74 12                   je     dd
  cb:   66 b8 64 00 00 00       mov    $0x64,%eax
  d1:   66 e8 fc ff ff ff       calll  d3
  d7:   66 e8 fc ff ff ff       calll  d9
  dd:   66 89 e0                mov    %esp,%eax
  e0:   66 e8 fc ff ff ff       calll  e2
  e6:   67 c7 44 24 1c 00 ec    addr32 movw $0xec00,0x1c(%esp)
  ed:   67 c7 44 24 10 02 00    addr32 movw $0x2,0x10(%esp)
  f4:   66 31 c9                xor    %ecx,%ecx
  f7:   66 89 e2                mov    %esp,%edx
  fa:   66 b8 15 00 00 00       mov    $0x15,%eax
 100:   66 e8 fc ff ff ff       calll  102
 106:   66 e8 fc ff ff ff       calll  108
 10c:   67 66 8d 44 24 2c       addr32 lea 0x2c(%esp),%eax
 112:   66 e8 fc ff ff ff       calll  114
 118:   67 c7 44 24 48 05 03    addr32 movw $0x305,0x48(%esp)
 11f:   66 31 c9                xor    %ecx,%ecx
 122:   67 66 8d 54 24 2c       addr32 lea 0x2c(%esp),%edx
 128:   66 b8 16 00 00 00       mov    $0x16,%eax
 12e:   66 e8 fc ff ff ff       calll  130
 134:   66 e8 fc ff ff ff       calll  136
 13a:   66 83 3e 00 00 05       cmpl   $0x5,0x0
 140:   7e 6c                   jle    1ae
 142:   67 66 8d 44 24 58       addr32 lea 0x58(%esp),%eax
 148:   66 e8 fc ff ff ff       calll  14a
 14e:   67 c7 44 24 74 80 e9    addr32 movw $0xe980,0x74(%esp)
 155:   67 66 c7 44 24 6c 43    addr32 movl $0x47534943,0x6c(%esp)
 15c:   49 53 47
 15f:   67 66 8d 8c 24 84 00    addr32 lea 0x84(%esp),%ecx
 166:   00 00
 168:   67 66 8d 54 24 58       addr32 lea 0x58(%esp),%edx
 16e:   66 b8 15 00 00 00       mov    $0x15,%eax
 174:   66 e8 fc ff ff ff       calll  176
 17a:   67 66 8b 84 24 a0 00    addr32 mov 0xa0(%esp),%eax
 181:   00 00
 183:   66 a3 60 00             mov    %eax,0x60
 187:   67 66 8b 84 24 94 00    addr32 mov 0x94(%esp),%eax
 18e:   00 00
 190:   66 a3 64 00             mov    %eax,0x64
 194:   67 66 8b 84 24 9c 00    addr32 mov 0x9c(%esp),%eax
 19b:   00 00
 19d:   66 a3 68 00             mov    %eax,0x68
 1a1:   67 66 8b 84 24 98 00    addr32 mov 0x98(%esp),%eax
 1a8:   00 00
 1aa:   66 a3 6c 00             mov    %eax,0x6c
 1ae:   66 e8 fc ff ff ff       calll  1b0
 1b4:   66 e8 fc ff ff ff       calll  1b6

注意
第一 -Mi8086选项,使用16位模式反汇编
第二main.o中只有一个main函数,其他函数都内联了
第三main没有ret,因为最后一个函数go_to_protected_mode有noreturn属性
第三66和67前缀被使用,因此是32位操作模式
第四header.S中的calll main也是32位调用
第五,使用了-fomit-frame-pointer选项,但是使用建立了栈帧,不知为何?
上一篇:系统启动(5)setup
下一篇:系统启动(7)main.c