11

this is the problem:
When I link my scripts in C, using ld, when I generate elf32-i386 files as output format in ld, putting it as OUTPUT_FORMAT() in the ld script, I dont have any error, but if I try to put in this last OUTPUT_FORMAT() "binary" or try to output a file with .bin extension, I get a mixture of errors like:

kernel.o: In function `k_main':
kernel.c:(.text+0xe): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelutils.o: In function `k_clear_screen':
kernelutils.c:(.text+0xc): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelutils.o: In function `k_clear_screen_front':
kernelutils.c:(.text+0x56): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelutils.o: In function `k_printf':
kernelutils.c:(.text+0xa0): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelutils.o: In function `k_sleep_3sec':
kernelutils.c:(.text+0x152): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelmalloc.o:kernelmalloc.c:(.text+0xc): more undefined references to `_GLOBAL_OFFSET_TABLE_' follow

This not only happens when compiling specific scripts, all scripts that try to use ld to link, or gcc since this calls ld, die in the attempt of get a binary with .bin extension.
When showing the symbols of one of the executables (kernel.o in the output of above) I see that the symbol _GLOBAL_OFFSET_TABLE_ isnt defined, and the most scary part, all the functions that returned error in the error output of above have their symbols removed, this is the nm output:

cristian@mymethodman:~/Desktop/kernel/0.0.3/Archivos$ nm kernel.o
         U _GLOBAL_OFFSET_TABLE_
         U k_clear_screen
         U k_clear_screen_front
00000000 T k_main
         U k_malloc
         U k_printf
         U k_sleep_3sec
00000000 T __x86.get_pc_thunk.bx

How I can solve this? I will leave the linker script below to ensure it isn a problem of the .ld file, with both "to get elf" and "to get binary" versions. Thanks in advance!

Ld scripts:
To get binary:

ENTRY(loader)
OUTPUT_FORMAT(binary)

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 = .;
   }
}

To get ELF:

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 = .;
   }
}

As yo ucan see between both only changes the OUTPUT_FORMAT() line.

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
Rottenheimer2
  • 425
  • 1
  • 5
  • 13
  • 2
    Looks like your host GCC environment (Likely a newer version of something like Ubuntu 16.04+ or Debian 9+) is generating position independent code. When you compile with _GCC_ you might want to try and compile all the files with `-fno-pic` . This is a good reason to use a GCC cross compiler for Operating System development. You can read about creating one here: http://wiki.osdev.org/GCC_Cross-Compiler – Michael Petch Jul 31 '17 at 18:03
  • Thanks, I will build the cross compiler – Rottenheimer2 Jul 31 '17 at 18:14
  • On a side note - why are you generating a binary file? I know you were using a multiboot compliant loader previously. To use a binary file will likely cause you issues unless you were now writing your own bootloader or you have altered your multiboot header to support the a.out kludge. – Michael Petch Jul 31 '17 at 18:17
  • @MichaelPetch I had a similar problem I am trying to debug. I am using `-fpie` with GCC but the linker is emitting GOT-relative relocation entries. I'm sure I've used an incorrect set of input flags for this to happen (even feeding the binaries into IDA Pro it reports to me that the binary uses "non-standard" relocations!). Any thoughts? Similar to the OP, `_GLOBAL_OFFSET_TABLE_` is undefined and there is no `.got` section. Indeed removing `-fpic` from the argument set prevented the GOT-relative relocations (now ABS) (but still no `.got` section). Would you mind helping me to understand? – sherrellbc May 18 '19 at 10:42

1 Answers1

21

Your toolchain probably defaults to generating position-independent executables (PIE). Try compiling with gcc -fno-pie.

If you want to keep PIE for security reasons, you'll need a more complicated linker script and something that performs the initial relocation (such as a dynamic linker, but simpler constructions are possible as well).

Florian Weimer
  • 32,022
  • 3
  • 48
  • 92
  • 1
    I've run into a similar problem. I've written a runtime ELF relocator for an ARM target and the linker will emit GOT-relative relocation entries. In the same way as shown here, there _is_ a symbol `_GLOBAL_OFFSET_TABLE_`, but it is undefined and not associated to any section (because there is no `.got` section emitted). I was explicitly compiling the code to be PIE (.e.g. `-fpie`). In what ways is a more complicated linker script needed when generating PIE code? Was also using GCC if that matters. Removing `-fpie` prevented this from happening. Why is that? – sherrellbc May 18 '19 at 10:26