代码之家  ›  专栏  ›  技术社区  ›  R0M2

为什么“GCC”忽略汇编代码的-fno pic

  •  0
  • R0M2  · 技术社区  · 2 年前

    我正在写一个操作系统,我想切换到长模式。 问题是我的交叉编译器( x86_64-elf-gcc )即使我通过了 -fno-pic 选项

    靴子s

    /* boot.S - bootstrap the kernel */
    /* https://www.kernel.org/doc/Documentation/x86/boot.txt */
        
    
    #include <boot/param.h>
    #include <asm/control_registers.h>
        
        /* 32-bit startup code. */
        .code32
        .text
        .global _start
        .type _start, @function
    _start:
        /* Clear DF flag */
        cld
        
        /* Setup stack */
        movl    $stack_top, %esp
    
        /* Check Multiboot2 */
        call    check_multiboot2
        testl   %eax, %eax
        jnz wrong_multiboot2
    
        /* Check CPUID */
        call    check_cpuid
        testl   %eax, %eax
        jnz no_cpuid
    
        /* Check if CPU can run in long mode */
        call    check_longmode
        testl   %eax, %eax
        jnz no_longmode
        
        /* TODO: Check the KEEP_SEGMENTS flag. */   
    
        /* Update the Global Descriptor Table with 64-bit segments */
        lgdt    gdt64
    
        /* Enable PAE */
        movl    %cr4, %eax
        orl $(1 << X86_CR4_PAE_BIT), %eax
        movl    %eax, %cr4
    
        /* TODO: Build the structure for paging. */
        
        /* TODO: Transition to long mode. */
    
        movl    $0x2f4b2f4f, 0xb8000
        
        cli
    1:  hlt
        jmp 1b
    wrong_multiboot2:
        movl    $'0, %eax
        jmp error
    no_cpuid:
        movl    $'1, %eax
        jmp error
    no_longmode:
        movl    $'2, %eax   
    error:
        movl    $0x4f524f45, (0xb8000)
        movl    $0x4f3a4f52, (0xb8004)
        movl    $0x4f204f20, (0xb8008)
        movb    %al, (0xb800a)
    1:  hlt
        jmp 1b
    
        
    #include "check.S"
    
        
        .section .rodata
        /* GDT */
    gdt64:
        .word   gdt_end - gdt - 1   /* limit */
        .quad   gdt         /* base */
    gdt:
        .quad   0           /* Null Descriptor */
        .quad   0x00af9a000000ffff  /* Kernel Mode Code Segment */
        .quad   0x00cf92000000ffff  /* Kernel Mode Data Segment */
        .quad   0x00affa000000ffff  /* User Mode Code Segment */
        .quad   0x00cff2000000ffff  /* User Mode Data Segment */
                        /* TODO: Task State Segment */
    gdt_end:    
    
        
        .bss
        /* Stack */
        .balign 4
    stack_bottom:
        .fill   STACK_SIZE, 1, 0
    stack_top:
    

    检查s

    /* check.S : check for multiboot2, cpuid, long mode */
    
    #include <boot/multiboot2.h>
        
    /* Check multiboot2 */
    check_multiboot2:   
        cmpl    $MULTIBOOT2_BOOTLOADER_MAGIC, %eax
        jne .Lcheck_wrong_multiboot2
        xorl    %eax, %eax
        ret
    .Lcheck_wrong_multiboot2:
        movl    $1, %eax
        ret
    
    /* Check if CPUID is supported by attempting to flip the ID bit (bit 21) in
       the FLAGS register. If we can flip it, CPUID is available. */
    check_cpuid:
        pushf
        push    $0
        popf
        
        /* Copy FLAGS in to EAX via stack */
        pushfl
        popl    %eax
    
        /* Copy to EBX as well for comparing later on */
        movl    %eax, %ebx
    
        /* Flip the ID bit */
        xorl    $(1 << 21), %eax
    
        /* Copy EAX to FLAGS via the stack */
        pushl   %eax
        popfl
    
        /* Copy FLAGS back to EAX (with the flipped bit if CPUID is supported) */
        pushfl
        popl    %eax
    
        /* Restore FLAGS from the old version stored in ECX (i.e. flipping the ID bit
           back if it was ever flipped). */
        /* push ecx */
    
        /* Compare EAX and EBX. If they are equal then that means the bit wasn't
        flipped, and CPUID isn't supported. */
        cmpl    %eax, %ebx
        jz  .Lcheck_no_cpuid
        popf
        xorl    %eax, %eax
        ret
    .Lcheck_no_cpuid:
        popf
        movl    $1, %eax
        ret
    
    /* Check if CPU can support long mode (64 bits) */
    check_longmode:
        pushf
        push    $0
        popf
        
        /* test if extended processor info in available */
        /* implicit argument for cpuid */
        movl    $0x80000000, %eax
        /* get highest supported argument */
        cpuid
        /* it needs to be at least 0x80000001 */
        cmpl    $0x80000001, %eax     
        jb  .Lcheck_no_longmode
    
        /* use extended info to test if long mode is available */
        /* argument for extended processor info */
        movl    $0x80000001, %eax     
        cpuid
        /* test if the LM-bit is set in the D-register */
        testl $(1 << 29), %edx
        /* If it's not set, there is no long mode */
        jz  .Lcheck_no_longmode
        popf
        xorl    %eax, %eax  
        ret
    .Lcheck_no_longmode:
        popf
        movl    $1, %eax
        ret
    

    我用 x86_64-elf-gcc -Wall -Wextra -nostdlib -lgcc -mno-red-zone -ffreestanding -std=gnu99 -fno-pic -c src/boot/boot.S -o build/boot.o -I include

    这是我们的目标 boot.o

    0000000000000000 <_start>:
       0:   fc                      cld    
       1:   bc 00 00 00 00          mov    $0x0,%esp
       6:   e8 6d 00 00 00          call   78 <check_multiboot2>
       b:   85 c0                   test   %eax,%eax
       d:   75 30                   jne    3f <wrong_multiboot2>
       f:   e8 74 00 00 00          call   88 <check_cpuid>
      14:   85 c0                   test   %eax,%eax
      16:   75 2e                   jne    46 <no_cpuid>
      18:   e8 8b 00 00 00          call   a8 <check_longmode>
      1d:   85 c0                   test   %eax,%eax
      1f:   75 2c                   jne    4d <no_longmode>
      21:   0f 01 15 00 00 00 00    lgdt   0x0(%rip)        # 28 <_start+0x28>
      28:   0f 20 e0                mov    %cr4,%rax
      2b:   83 c8 20                or     $0x20,%eax
      2e:   0f 22 e0                mov    %rax,%cr4
      31:   c7 05 00 80 0b 00 4f    movl   $0x2f4b2f4f,0xb8000(%rip)        # b803b <stack_top+0xb403b>
      38:   2f 4b 2f 
      3b:   fa                      cli    
      3c:   f4                      hlt    
      3d:   eb fd                   jmp    3c <_start+0x3c>
    
    000000000000003f <wrong_multiboot2>:
      3f:   b8 30 00 00 00          mov    $0x30,%eax
      44:   eb 0c                   jmp    52 <error>
    
    0000000000000046 <no_cpuid>:
      46:   b8 31 00 00 00          mov    $0x31,%eax
      4b:   eb 05                   jmp    52 <error>
    
    000000000000004d <no_longmode>:
      4d:   b8 32 00 00 00          mov    $0x32,%eax
    
    0000000000000052 <error>:
      52:   c7 05 00 80 0b 00 45    movl   $0x4f524f45,0xb8000(%rip)        # b805c <stack_top+0xb405c>
      59:   4f 52 4f 
      5c:   c7 05 04 80 0b 00 52    movl   $0x4f3a4f52,0xb8004(%rip)        # b806a <stack_top+0xb406a>
      63:   4f 3a 4f 
      66:   c7 05 08 80 0b 00 20    movl   $0x4f204f20,0xb8008(%rip)        # b8078 <stack_top+0xb4078>
      6d:   4f 20 4f 
      70:   a2 0a 80 0b 00 f4 eb    movabs %al,0x3dfdebf4000b800a
      77:   fd  
    
    0000000000000078 <check_multiboot2>:
      78:   3d 89 62 d7 36          cmp    $0x36d76289,%eax
      7d:   75 03                   jne    82 <check_multiboot2+0xa>
      7f:   31 c0                   xor    %eax,%eax
      81:   c3                      ret    
      82:   b8 01 00 00 00          mov    $0x1,%eax
      87:   c3                      ret    
    
    0000000000000088 <check_cpuid>:
      88:   9c                      pushf  
      89:   6a 00                   push   $0x0
      8b:   9d                      popf   
      8c:   9c                      pushf  
      8d:   58                      pop    %rax
      8e:   89 c3                   mov    %eax,%ebx
      90:   35 00 00 20 00          xor    $0x200000,%eax
      95:   50                      push   %rax
      96:   9d                      popf   
      97:   9c                      pushf  
      98:   58                      pop    %rax
      99:   39 c3                   cmp    %eax,%ebx
      9b:   74 04                   je     a1 <check_cpuid+0x19>
      9d:   9d                      popf   
      9e:   31 c0                   xor    %eax,%eax
      a0:   c3                      ret    
      a1:   9d                      popf   
      a2:   b8 01 00 00 00          mov    $0x1,%eax
      a7:   c3                      ret    
    
    00000000000000a8 <check_longmode>:
      a8:   9c                      pushf  
      a9:   6a 00                   push   $0x0
      ab:   9d                      popf   
      ac:   b8 00 00 00 80          mov    $0x80000000,%eax
      b1:   0f a2                   cpuid  
      b3:   3d 01 00 00 80          cmp    $0x80000001,%eax
      b8:   72 13                   jb     cd <check_longmode+0x25>
      ba:   b8 01 00 00 80          mov    $0x80000001,%eax
      bf:   0f a2                   cpuid  
      c1:   f7 c2 00 00 00 20       test   $0x20000000,%edx
      c7:   74 04                   je     cd <check_longmode+0x25>
      c9:   9d                      popf   
      ca:   31 c0                   xor    %eax,%eax
      cc:   c3                      ret    
      cd:   9d                      popf   
      ce:   b8 01 00 00 00          mov    $0x1,%eax
      d3:   c3                      ret    
    

    我们可以看到 movl $0x2f4b2f4f, 0xb8000 被编译成 movl $0x2f4b2f4f,0xb8000(%rip) 所以我不能正确地从开始写入VGA文本缓冲区 0xb8000 .

    我也在接受其他建议。

    0 回复  |  直到 2 年前