[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Bug ld/6945] New: ld -r severely broken on 64-bit mingw / pe-x86-64

From: mikpe at it dot uu dot se
Subject: [Bug ld/6945] New: ld -r severely broken on 64-bit mingw / pe-x86-64
Date: 6 Oct 2008 12:22:08 -0000

x86_64-pc-mingw32-ld -r runs without warnings, but gcc jump tables in the
resulting .o file are broken. At runtime a switch() that references a jump table
now branches off to la-la land and the process crashes.

My x86_64-pc-mingw32 cross toolchain is composed of binutils-
and gcc-4.4.0 20080926, with runtime libs from mingw-w64-snapshot-20080917.
The cross toolchain was compiled by a i686-pc-cygwin native toolchain composed
of binutils-2.18.91 and gcc-4.3.2. The host runs Win XP 64 Pro.

To reproduce, compile and link the file below (bug.c):
1. x86_64-pc-mingw32-gcc -O -c bug.c
2. x86_64-pc-mingw32-ld -r -o bug2.o bug.o
3. x86_64-pc-mingw32-gcc -o bug bug.o
4. x86_64-pc-mingw32-gcc -o bug2 bug2.o

Running ./bug works and produces output like:
L90 == 000000000040165A
L95 == 0000000000403000
L95.L90_minus_L95 == -6566, L95 + -6566 == 000000000040165A

However, running ./bug2 instead fails with:
L90 == 000000000040165A
L95 == 0000000000403000
L95.L90_minus_L95 == -6406, L95 + -6406 == 00000000004016FA

This error does not occur when compiling for 32-bit mingw, or when compiling for
Linux or Solaris (32- or 64-bit x86).

The source code for bug.c follows below. The inline asm() block constructs a gcc
switch() jump table in "pic" mode: entries aren't code lables but the
differences from the table itself to the code labels. The rest of the code just
verifies the contents of the jump table.

#include <stdio.h>

struct L95 {    /* mimics a gcc -fpic jump table */
    int L90_minus_L95;
extern const struct L95 L95;

struct L95info {        /* provides the actual target labels */
    void *L90;
struct L95info L95info;

void __attribute__((noinline)) foo(void)
        "leaq _L95info(%rip), %rax\n\t"
        "leaq L90(%rip), %rdx\n\t"
        "movq %rdx, 0(%rax)\n\t"
        ".section .rdata,\"dr\"\n\t"
        ".align 4\n"
        ".long L90-_L95\n\t"
        "movl $1, %eax\n"
        "addl %eax, %eax");

int main(void)
    int diff;
    void *result;

    printf("L90 == %p\n", L95info.L90);
    printf("L95 == %p\n", &L95);
    diff = L95.L90_minus_L95;
    result = (char*)&L95 + diff;
    printf("L95.L90_minus_L95 == %d, L95 + %d == %p\n",
           diff, diff, result);
    if (result != L95info.L90) {
        return 1;
    return 0;

           Summary: ld -r severely broken on 64-bit mingw / pe-x86-64
           Product: binutils
           Version: 2.19
            Status: NEW
          Severity: critical
          Priority: P2
         Component: ld
        AssignedTo: unassigned at sources dot redhat dot com
        ReportedBy: mikpe at it dot uu dot se
                CC: bug-binutils at gnu dot org
  GCC host triplet: i686-pc-cygwin
GCC target triplet: x86_64-pc-mingw32


------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]