We see some weird address generation when using ld and objcopy to generate parts of bios images (upcoming LinuxBIOS version 3) The first thing that is required is the reset vector. It's 16 bytes at 0xfffffff0 (aliased to f000:fff0 in real mode). It jumps into the real code which is placed at 0xffffe000 (0xe000 in the current segment). --------- 8< reset.s -------------------------- SEGMENT_SIZE = 0x10000 RVECTOR = 0x00010 .code16 .globl _start _start: jmp SEGMENT_SIZE-(0x1f00 +0xf0 +RVECTOR) .byte 0 .ascii "2007/02/01" .word 0 ----------------- 8< -------------------------- I build it with: as reset.s -o reset.o and link it: ld -Ttext 0xfffffff0 reset.o -o reset.elf objcopy -O binary -S reset.elf reset.bin Now I disassemble it: ndisasm -o 0xfffffff0 reset.bin | head -1 FFFFFFF0 E9FEDF jmp 0xdff1 Oops. It is obviously wrong. But why? Alternatively I omit the objcopy step but I basically do the same (do I?): ld -Ttext 0xfffffff0 -s --oformat binary reset.o -o reset.bin ndisasm -o 0xfffffff0 reset.bin | head -1 FFFFFFF0 E90DE0 jmp 0xe000 Phew. It works here. But why? What's the difference? We don't really want to use the second version, because the intermediate elf binary is nice to dump a symbal table using nm -e reset.elf. People are sometimes heavily relying on this: 0000000000000010 a RVECTOR 0000000000010000 a SEGMENT_SIZE 00000000fffffff0 T _start Version is binutils 2.17.50.0.5 from OpenSUSE 10.2 but I other people using some version of RH FC seem to see the same problem.
We have bash-3.1$ cat foo.s SEGMENT_SIZE = 0x10000 RVECTOR = 0x00010 .code16 .globl _start _start: #jmp 0xfef0 jmp SEGMENT_SIZE-(0x1f00 +0xf0 +RVECTOR) bash-3.1$ gcc -c -m32 foo.s bash-3.1$ ./objdump -Mi8086 -dr foo.o foo.o: file format elf32-i386 Disassembly of section .text: 00000000 <_start>: 0: e9 fe df jmp ffffe001 <SEGMENT_SIZE+0xfffee001> 1: R_386_PC16 *ABS* That is a relocation against ABS section. But many ELF linkers have if (r_symndx == 0) { /* r_symndx will be zero only for relocs against symbols from removed linkonce sections, or sections discarded by a linker script. For these relocs, we just want the section contents zeroed. Avoid any special processing. */ _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset); continue; } The above comment and code are certainly incorrect for this testcase.
A patch is posted at http://sourceware.org/ml/binutils/2007-02/msg00036.html
I can confirm that the right binary output is produced in my case when this patch is applied.
(In reply to comment #3) > I can confirm that the right binary output is produced in my case when this > patch is applied. Are you running binutils on a 64bit OS?
Relocation against STN_UNDEF is well defined by the gABI. Here is the updated patch: http://sourceware.org/ml/binutils/2007-03/msg00029.html
http://sourceware.org/ml/binutils-cvs/2007-03/msg00029.html