Subject: forwarded message from MDaemon@pruimpit
From: [email-masked] (Jon Thackray)

15 Sep 1997 03:48:37 -0700
Message-ID: <[email-masked]>
To: [email-masked]

What's going on here? Did my message get to the list?
------- start of forwarded message (RFC 934 encapsulation) -------
Content-Length: 8611
Reply-To: MDaemon@PRUIMPIT
From: MDaemon@PRUIMPIT
To: jont
Subject: Warning: No Such User!
Date: Sat, 13 Sep 97 12:42:58 +0100

gnu-win32-outgoing@PRUIMPIT - no such user here.

- --ORIGINAL MESSAGE BEGINS--
Date: Wed, 3 Sep 1997 14:33:08 +0100
From: Jon Thackray <[email-masked]>
To: [email-masked]
Subject: b18 linker problems
Sender: [email-masked]
Status: N 

It seems that the b18 linker does incorrect things with pc relative
relocation to symbols not in the .text section (or more specifically
not in section 0, as will be revealed later). The following email
contains a number of exhibits demonstrating the problem, and where I
think it lies. First is a small assembler program demonstrating the
problem. The problem can be shown under as if there is a pc relative
relocation to a symbol not in the .text section, as in the example
below. If one rearranges the sections by replaacing .text with .text$i
and vice versa then all is ok. A language translator which does not
place its text in section 0 may also encounter the problem. I include
three outputs from objdump of the link of this program. The first link
was done with a raw b18 and demonstrates the problem. The second link
was done using b17 ld, and shows that the problem is a regression. The
third link is done with a version of ld that I have modified to
produce a fix for the problem.

The problem seems to lie in a combination of
_bfd_coff_generic_relocate_section within cofflink.c and
coff_i386_rtype_to_howto in coff-i386.c I include annotated code from
cofflink.c and coff-i386.c demonstrating where I think the problem
lies.

	.section	.text$i
	.global	foo1
	.global	foo2
foo1:	mov	$0, %eax
	ret
foo2:	mov	$1, %eax
	ret
	.text
	.global	main
	.global	foo1
	.global	foo2
main:	call	foo1
	call	foo2
	mov	$0, %eax
	ret

with b18 ld

bash$ objdump --disassemble foo.exe

foo.exe:     file format pei-i386

Disassembly of section .text:

00401000 <main>:
     0:	e8 1b 00 00 00 	call   00401020 <etext+4>
     5:	e8 1c 00 00 00 	call   00401026 <etext+a>
     a:	b8 00 00 00 00 	movl   $0x0,%eax
     f:	c3             	ret    

00401010 <foo1>:
     0:	b8 00 00 00 00 	movl   $0x0,%eax
     5:	c3             	ret    

00401016 <foo2>:
     0:	b8 01 00 00 00 	movl   $0x1,%eax
     5:	c3             	ret    

0040101c <etext>:
	...

with b17 ld

objdump --disassemble foo.exe

foo.exe:     file format pei-i386

Disassembly of section .text:

00401000 <main>:
     0:	e8 0b 00 00 00 	call   00401010 <foo1>
     5:	e8 0c 00 00 00 	call   00401016 <foo2>
     a:	b8 00 00 00 00 	movl   $0x0,%eax
     f:	c3             	ret    

00401010 <foo1>:
     0:	b8 00 00 00 00 	movl   $0x0,%eax
     5:	c3             	ret    

00401016 <foo2>:
     0:	b8 01 00 00 00 	movl   $0x1,%eax
     5:	c3             	ret    

0040101c <etext>:
	...

After modifying b18

objdump --disassemble foo.exe

foo.exe:     file format pei-i386

Disassembly of section .text:

00401000 <main>:
     0:	e8 0b 00 00 00 	call   00401010 <foo1>
     5:	e8 0c 00 00 00 	call   00401016 <foo2>
     a:	b8 00 00 00 00 	movl   $0x0,%eax
     f:	c3             	ret    

00401010 <foo1>:
     0:	b8 00 00 00 00 	movl   $0x0,%eax
     5:	c3             	ret    

00401016 <foo2>:
     0:	b8 01 00 00 00 	movl   $0x1,%eax
     5:	c3             	ret    

0040101c <etext>:
	...

Annotated excerpt from bfd/coff-i386.c (annotations within C style
comments)

static reloc_howto_type *
coff_i386_rtype_to_howto (abfd, sec, rel, h, sym, addendp)
     bfd *abfd;
     asection *sec;
     struct internal_reloc *rel;
     struct coff_link_hash_entry *h;
     struct internal_syment *sym;
     bfd_vma *addendp;
{

  reloc_howto_type *howto;

  howto = howto_table + rel->r_type;

#ifdef COFF_WITH_PE
  *addendp = 0;  /* For gun-win32 on the PC, this will happen */
#endif

  if (howto->pc_relative)
    *addendp += sec->vma;

  if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0)
    {
      /* This is a common symbol.  The section contents include the
	 size (sym->n_value) as an addend.  The relocate_section
	 function will be adding in the final value of the symbol.  We
	 need to subtract out the current size in order to get the
	 correct result.  */
 
      BFD_ASSERT (h != NULL);

#ifndef COFF_WITH_PE
      /* I think we *do* want to bypass this.  If we don't, I have seen some data
	 parameters get the wrong relcation address.  If I link two versions
	 with and without this section bypassed and then do a binary comparison,
	 the addresses which are different can be looked up in the map.  The 
	 case in which this section has been bypassed has addresses which correspond
	 to values I can find in the map */
      *addendp -= sym->n_value;
#endif
    }

  /* If the output symbol is common (in which case this must be a
     relocateable link), we need to add in the final size of the
     common symbol.  */
  if (h != NULL && h->root.type == bfd_link_hash_common) 
    *addendp += h->root.u.c.size;

#ifdef COFF_WITH_PE
  if (howto->pc_relative)
    *addendp -= 4; /* This will also happen */

  if (rel->r_type == R_IMAGEBASE)
    {
      *addendp -= pe_data(sec->output_section->owner)->pe_opthdr.ImageBase;
    }
#endif

  return howto;
}

Annotated excerpt from bfd/cofflink.c (annotations within C style
comments)

      if (sym != NULL && sym->n_scnum != 0)
	addend = - sym->n_value;
      else
	addend = 0;

/* In the example case, addend is assigned the value -sym->n_value.
 * However, this is irrelevant because howto overwites the value of
 * addend to be -4 (to deal with the fact that the 386 computes
 * pc-relative addresses from the start of the next instruction,
 * whereas the address we'll subtract out later will be the address at
 * which the relocation takes place, ie 4 less). In the modified
 * example, where the section names are switched, addend is simply set
 * to zero.
 */
      howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h,
				       sym, &addend);
      if (howto == NULL)
	return false;

      /* If we are doing a relocateable link, then we can just ignore
         a PC relative reloc that is pcrel_offset.  It will already
         have the correct value.  If this is not a relocateable link,
         then we should ignore the symbol value.  */
      if (howto->pc_relative && howto->pcrel_offset)
	{
	  if (info->relocateable)
	    continue;
	  if (sym != NULL && sym->n_scnum != 0)
	    addend += sym->n_value;

/* This would undo the earlier subtraction, except that howto has
 * junked the result. The overall effect is that we end up pointing
 * to an address which is too large by an amount equal to the symbol
 * value.
 */
	}

A simple fix for the above is to leave out the two modifications of
addend by sym->n_value. This produces the corect result for the
example code above, and also for the code I was originally trying to
link. However, I suspect there is more to this than meets my eye.
- -
For help on using this list (especially unsubscribing), send a message to
"[email-masked]" with one line of text: "help".

------- end -------
-
For help on using this list (especially unsubscribing), send a message to
"[email-masked]" with one line of text: "help".