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-2.19.50.20081006 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 ERROR 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) { asm( "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" "_L95:\n\t" ".long L90-_L95\n\t" ".text\n\t" "movl $1, %eax\n" "L90:\n\t" "addl %eax, %eax"); } int main(void) { int diff; void *result; foo(); 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) { printf("ERROR\n"); 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 http://sourceware.org/bugzilla/show_bug.cgi?id=6945 ------- You are receiving this mail because: ------- You are on the CC list for the bug, or are watching someone who is. _______________________________________________ bug-binutils mailing list bug-binutils@gnu.org http://lists.gnu.org/mailman/listinfo/bug-binutils