Bug 3958 - ELF linker failed to handle relocation against STN_UNDEF
Summary: ELF linker failed to handle relocation against STN_UNDEF
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.17
: P2 normal
Target Milestone: ---
Assignee: Alan Modra
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2007-02-02 14:22 UTC by Stefan Reinauer
Modified: 2007-03-07 10:06 UTC (History)
2 users (show)

See Also:
Host: i586-suse-linux
Target: i586-suse-linux
Build: i586-suse-linux
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Stefan Reinauer 2007-02-02 14:22:59 UTC
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.
Comment 1 H.J. Lu 2007-02-03 01:52:27 UTC
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.
Comment 2 H.J. Lu 2007-02-03 16:45:55 UTC
A patch is posted at

http://sourceware.org/ml/binutils/2007-02/msg00036.html
Comment 3 Stefan Reinauer 2007-02-03 23:14:52 UTC
I can confirm that the right binary output is produced in my case when this
patch is applied.
Comment 4 H.J. Lu 2007-02-04 08:39:26 UTC
(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?
Comment 5 H.J. Lu 2007-03-03 23:06:34 UTC
Relocation against STN_UNDEF is well defined by the gABI. Here is the updated
patch:

http://sourceware.org/ml/binutils/2007-03/msg00029.html