NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
toolchain/43314: pc relative relocations are "off by 1*size" on vax
>Number: 43314
>Category: toolchain
>Synopsis: toolchain
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: toolchain-manager
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sun May 16 11:05:00 +0000 2010
>Originator: Martin Husemann
>Release: NetBSD 5.99.29
>Organization:
The NetBSD Foundation, Inc.
>Environment:
System: NetBSD dead-to-the-world.duskware.de 5.99.29 NetBSD 5.99.29 (DEAD) #31:
Wed May 12 19:07:50 CEST 2010
martin%night-porter.duskware.de@localhost:/usr/src/sys/arch/vax/compile/DEAD vax
Architecture: vax
Machine: vax
>Description:
While analyzing the broken C++ exception handling on vax I ran into this
problem (.eh* frame descriptions use 32bit pc relative references to a
32bit value storing the function pointer to call as "personality" function,
but the unwinding code dereferences a 32bit value 4 bytes below that pointer
and crashes).
I couldn't find the ultimate reference describing the %pcrel() asm pseudo
op, so I'm not sure if this is a bug in binutils, or if gcc should be
modified (patch below) to output different references.
>How-To-Repeat:
Run this small sample program and wonder, why the relative addresses are
4, 2 or 1 byte lower than expected:
--8<--
/*
* demo program to show strange %pcrel behaviour on vax:
* exception handling frame descriptors include code like
* .4byte %pcrel32(DW.ref.__gxx_personality_v0)
* to reference pc relatvie to a 4 byte value containing a pointer
* to __gxx_personality_v0 (a "peronality" function), but the unwinding
* code ends up dereferencing the memory 4 byte below that value.
*/
#include <stdio.h>
#include <inttypes.h>
int main(int argc, char **argv)
{
const char *str;
extern const long ref4;
extern const short ref2;
extern const signed char ref1;
__asm(
".section .rodata\n"
".globl ref_string\n"
"ref_string: .string \"abcdefghijklmnopq\"\n"
".globl ref4\n"
"ref4:\n"
".4byte %%pcrel32(ref_string+8)\n"
".globl ref2\n"
"ref2:\n"
".2byte %%pcrel16(ref_string+6)\n"
".globl ref1\n"
"ref1:\n"
".byte %%pcrel8(ref_string+5)\n"
".text" ::);
/* Test 4 byte pcrelative access */
str = (const char*)((uintptr_t)&ref4 + ref4);
printf("pcrel32 at %p value %ld pointing to %p -> %s\n",
&ref4, ref4, str, str);
str = (const char*)((uintptr_t)&ref2 + ref2);
printf("pcrel16 at %p value %d pointing to %p -> %s\n",
&ref2, ref2, str, str);
str = (const char*)((uintptr_t)&ref1 + ref1);
printf("pcrel8 at %p value %d pointing to %p -> %s\n",
&ref1, ref1, str, str);
return 0;
}
-->8--
It prints:
pcrel32 at 0x272c8 value -14 pointing to 0x272ba -> efghijklmnopq
pcrel16 at 0x272cc value -18 pointing to 0x272ba -> efghijklmnopq
pcrel8 at 0x272ce value -20 pointing to 0x272ba -> efghijklmnopq
but the output should start at ref_string+8 ("ijkl...") etc.
>Fix:
If this is not considered a binutils bug, we could adjust gcc like this
(untested):
Index: elf.h
===================================================================
RCS file: /cvsroot/src/gnu/dist/gcc4/gcc/config/vax/elf.h,v
retrieving revision 1.3
diff -c -u -r1.3 elf.h
--- elf.h 31 Mar 2007 05:55:11 -0000 1.3
+++ elf.h 16 May 2010 10:56:13 -0000
@@ -107,5 +107,5 @@
fputs (integer_asm_op (SIZE, FALSE), FILE); \
fprintf (FILE, "%%pcrel%d(", SIZE * 8); \
assemble_name (FILE, LABEL); \
- fputc (')', FILE); \
+ fprintf (FILE, "+%d)", SIZE); \
} while (0)
Home |
Main Index |
Thread Index |
Old Index