title: Linker error setting loading GDT register with LGDT instruction using Inline assembly
body: <p>I was compiling my prototype of prototype of a kernel (sounds weird, but it really doesn't matter) and in the installation I need to link the ASM file to a C file compiled with gcc to get a executable that could be used as kernel.
  The problem is that, after implementing a swap to protected mode from real mode, I get this error at linking the kernel.c and loader.asm scripts:</p>
  
  <p>Code:</p>
  
  <pre><code>kernel.c:(.text+0x1e1): undefined reference to `gdtr'
  </code></pre>
  
  <p>I will explain how all process of installation is and I will put the codes below.
  Installation steps:
  1: Compile asm:
  Code:</p>
  
  <pre><code>nasm -f elf32 loader.asm -o kasm.o
  </code></pre>
  
  <p>2: Compile .c :
  Code:</p>
  
  <pre><code>gcc -m32 -ffreestanding -c kernel.c -o kc.o
  </code></pre>
  
  <p>3: Link both:
  Code:</p>
  
  <pre><code>ld -m elf_i386 -T linker.ld -o kernel kasm.o kc.o
  </code></pre>
  
  <p>The complete error output is:
  Code:</p>
  
  <pre><code>kc.o: In function `k_enter_protected_mode':
  kernel.c:(.text+0x1e1): undefined reference to `gdtr'
  </code></pre>
  
  <p>The code looks like:
  Code:</p>
  
  <pre><code>/*
   *
   * kernel.c - version 0.0.1
   * This script is under the license of the distributed package, this license
   * can be found in the package itself
   * Script coded by Cristian Simón for the CKA Proyect
   * ----
   * License: GNU GPL v3
   * Coder: Cristian Simón
   * Proyect: CKA 
   * 
   */
  /* Output defines */
  #define BLACK_BGROUND 0X07 /* black background */
  #define WHITE_TXT 0x07 /* light gray on black text */
  #define GREEN_TXT 0x02 /* light green on black text */
  #define RED_TXT 0x04 /* light red on black text*/
  #define CYAN_TXT 0x03 /*light cyan on black text */
  #include &lt;stddef.h&gt;
  #include &lt;stdint.h&gt;
  #include &lt;cpuid.h&gt;
  void k_clear_screen();
  void k_sleep_3sec();
  unsigned int k_printf(char *message, unsigned int line, float color);
  void k_malloc(size_t sz);
  void k_free(void *mem);
  /* k_clear_screen : to clear the entire text screen */
  void k_clear_screen()
  {
      char *vidmem = (char *) 0xC00B8000;
      unsigned int i=0;
      while(i &lt; (80*25*2))
      {
          vidmem[i]=' ';
          i++;
          vidmem[i]=BLACK_BGROUND;
          i++;
      };
  }
  
  /* k_printf : the message and the line # */
  unsigned int k_printf(char *message, unsigned int line, float color)
  {
      char *vidmem = (char *) 0xC00B8000;
      unsigned int i=0;
  
      i=(line*80*2);
  
      while(*message!=0)
      {
          if(*message=='\n') /* check for a new line */
          {
              line++;
              i=(line*80*2);
              *message++;
          } else {
              vidmem[i]=*message;
              *message++;
              i++;
              vidmem[i]=color;
              i++;
          };
      };
  
      return(1);
  }
  
  /* 
  * k_sleep_3sec : to make a simple delay of aprox 3 sec, since is a nasty sleep, 
  * duration will vary
  * from system to system
  */
  void k_sleep_3sec()
  {
      int c = 1, d = 1;
      for ( c = 1 ; c &lt;= 20000 ; c++ )
      for ( d = 1 ; d &lt;= 20000 ; d++ )
      {}
  }
  /* 
  * Malloc and free functions for this kernel
  * Maybe change in the future, sure
  */
  static unsigned char our_memory[1024 * 1024]; /* reserve 1 MB for malloc */
  static size_t next_index = 0;
  int k_malloc_err;
  void k_malloc(size_t sz)
  {
      void *mem;
      if(sizeof our_memory - next_index &lt; sz){
          return NULL;
          k_malloc_err = 1;
      }
  
      mem = &amp;our_memory[next_index];
      next_index += sz;
      return mem;
  }
  void k_free(void *mem)
  {
     /* we cheat, and don't free anything. */
  }
  /* Schreduler */
  /*---*/
  /*
  * Our schreduler is a RTC (Run to Completion)
  * In the future we will add more schredulers or change the type
  * but for now this is what we got
  */
  int proc_number_count = 0;
  void k_schreduler(char *proc_name, unsigned int proc_prior)
  {
      proc_number_count = proc_number_count + 1;
      int proc_number = proc_number_count;
  }
  void k_enter_protected_mode()
  {
      __asm__ volatile ("cli;"          
          "lgdt (gdtr);"  
          "mov %eax, cr0;" 
          "or %al, 1;"    
          "mov cr0, %eax;" 
          "jmp 0x8,PModeMain;"
          "PModeMain:");
  }
  /*main function*/
  void k_main() 
  {
      k_clear_screen();
      k_printf(" Wellcome to", 0, WHITE_TXT);
      k_printf(" CKA!", 1, GREEN_TXT);
      k_printf("==============&gt;", 2, WHITE_TXT);
      k_printf(" CKA stands for C Kernel with Assembly", 3, WHITE_TXT);
      k_printf(" Version 0.0.1, =&gt; based in the job of Debashis Barman", 4, WHITE_TXT);
      k_printf(" Contact =&gt; assemblyislaw@gmail.com / blueshell@mail2tor.com", 5, WHITE_TXT);
      k_printf("           or in the github repository page", 6, WHITE_TXT);
      k_sleep_3sec();
      k_clear_screen();
      /* here start the magic */
      k_printf(" !===&gt; Starting Checkup &lt;===!", 0, WHITE_TXT);
      k_printf(" =-=-=-=-=-=-=-=-=-=-=-=-=-=-", 1, WHITE_TXT);
      k_printf("[KernelInfo] Woah! No Kernel Panic for now! Well, lets fix that...", 2, CYAN_TXT);
      k_printf("[Proc1] Checking for k_malloc() and k_free() kernel functions", 3, WHITE_TXT);
      k_malloc(15);
      if (k_malloc_err == 1){
          k_printf("[F-ERROR] Unable to use k_malloc, do you have enough memory?", 4, RED_TXT);
          while(1){
              int error_stayer = 1;
          }
  
      } else{ 
          k_printf("[Proc1] k_malloc and k_free found, resuming boot...", 4, GREEN_TXT);
      }
      k_enter_protected_mode();
      k_printf("[KernelInfo] Switched to protected mode successfully", 5, CYAN_TXT);
  
  }
  </code></pre>
  
  <h2>This was kernel.c</h2>
  
  <p>Code:</p>
  
  <pre><code>ENTRY(loader)
  OUTPUT_FORMAT(elf32-i386)
  
  SECTIONS {
     /* The kernel will live at 3GB + 1MB in the virtual
        address space, which will be mapped to 1MB in the
        physical address space. */
     . = 0xC0100000;
  
     .text : AT(ADDR(.text) - 0xC0000000) {
         *(.text)
         *(.rodata*)
     }
  
     .data ALIGN (0x1000) : AT(ADDR(.data) - 0xC0000000) {
         *(.data)
     }
  
     .bss : AT(ADDR(.bss) - 0xC0000000) {
         _sbss = .;
         *(COMMON)
         *(.bss)
         _ebss = .;
     }
  }
  </code></pre>
  
  <h2>This was the linker.ld</h2>
  
  <p>Code:</p>
  
  <pre><code>global _loader                          ; Make entry point visible to linker.
  extern k_main                           ; _main is defined elsewhere
  
  ; setting up the Multiboot header - see GRUB docs for details
  MODULEALIGN equ  1&lt;&lt;0             ; align loaded modules on page boundaries
  MEMINFO     equ  1&lt;&lt;1             ; provide memory map
  FLAGS       equ  MODULEALIGN | MEMINFO  ; this is the Multiboot 'flag' field
  MAGIC       equ    0x1BADB002     ; 'magic number' lets bootloader find the header
  CHECKSUM    equ -(MAGIC + FLAGS)  ; checksum required
  
  ; This is the virtual base address of kernel space. It must be used to convert virtual
  ; addresses into physical addresses until paging is enabled. Note that this is not
  ; the virtual address where the kernel image itself is loaded -- just the amount that must
  ; be subtracted from a virtual address to get a physical address.
  KERNEL_VIRTUAL_BASE equ 0xC0000000                  ; 3GB
  KERNEL_PAGE_NUMBER equ (KERNEL_VIRTUAL_BASE &gt;&gt; 22)  ; Page directory index of kernel's 4MB PTE.
  
  
  section .data
  align 0x1000
  BootPageDirectory:
      ; This page directory entry identity-maps the first 4MB of the 32-bit physical address space.
      ; All bits are clear except the following:
      ; bit 7: PS The kernel page is 4MB.
      ; bit 1: RW The kernel page is read/write.
      ; bit 0: P  The kernel page is present.
      ; This entry must be here -- otherwise the kernel will crash immediately after paging is
      ; enabled because it can't fetch the next instruction! It's ok to unmap this page later.
      dd 0x00000083
      times (KERNEL_PAGE_NUMBER - 1) dd 0                 ; Pages before kernel space.
      ; This page directory entry defines a 4MB page containing the kernel.
      dd 0x00000083
      times (1024 - KERNEL_PAGE_NUMBER - 1) dd 0  ; Pages after the kernel image.
  
  
  section .text
  align 4
  MultiBootHeader:
      dd MAGIC
      dd FLAGS
      dd CHECKSUM
  
  ; reserve initial kernel stack space -- that's 16k.
  STACKSIZE equ 0x4000
  
  ; setting up entry point for linker
  loader equ (_loader - 0xC0000000)
  global loader
  
  _loader:
      ; NOTE: Until paging is set up, the code must be position-independent and use physical
      ; addresses, not virtual ones!
      mov ecx, (BootPageDirectory - KERNEL_VIRTUAL_BASE)
      mov cr3, ecx                                        ; Load Page Directory Base Register.
  
      mov ecx, cr4
      or ecx, 0x00000010                          ; Set PSE bit in CR4 to enable 4MB pages.
      mov cr4, ecx
  
      mov ecx, cr0
      or ecx, 0x80000000                          ; Set PG bit in CR0 to enable paging.
      mov cr0, ecx
  
      ; Start fetching instructions in kernel space.
      ; Since eip at this point holds the physical address of this command (approximately 0x00100000)
      ; we need to do a long jump to the correct virtual address of StartInHigherHalf which is
      ; approximately 0xC0100000.
      lea ecx, [StartInHigherHalf]
      jmp ecx                                                     ; NOTE: Must be absolute jump!
  
  StartInHigherHalf:
      ; Unmap the identity-mapped first 4MB of physical address space. It should not be needed
      ; anymore.
      mov dword [BootPageDirectory], 0
      invlpg [0]
  
      ; NOTE: From now on, paging should be enabled. The first 4MB of physical address space is
      ; mapped starting at KERNEL_VIRTUAL_BASE. Everything is linked to this address, so no more
      ; position-independent code or funny business with virtual-to-physical address translation
      ; should be necessary. We now have a higher-half kernel.
      mov esp, stack+STACKSIZE           ; set up the stack
      push eax                           ; pass Multiboot magic number
  
      ; pass Multiboot info structure -- WARNING: This is a physical address and may not be
      ; in the first 4MB!
      push ebx
  
      call  k_main                 ; call kernel proper
      hlt                          ; halt machine should kernel return
  
  
  section .bss
  align 32
  stack:
      resb STACKSIZE      ; reserve 16k stack on a uint64_t boundary
  </code></pre>
  
  <h2>This was loader.asm</h2>
  
  <p>I tried to solve this transforming the ASM block in an advanced ASM block and parsing gdtr as an argument but I don't understand this last method
  How can I solve the error?</p>