[Bug compile/34456] New: ppc64le: "compile" command corrupts addresses of inferior symbols (-mcmodel=medium TOC16 relocation overflow)
abhay at sourceware dot org via Gdb-prs <[email protected]>
| Newsgroups | gmane.comp.gdb.bugs.discuss |
|---|---|
| Message-ID | <[email protected]/bugzilla/> |
https://sourceware.org/bugzilla/show_bug.cgi?id=34456
Bug ID: 34456
Summary: ppc64le: "compile" command corrupts addresses of
inferior symbols (-mcmodel=medium TOC16 relocation
overflow)
Product: gdb
Version: HEAD
Status: NEW
Severity: normal
Priority: P2
Component: compile
Assignee: unassigned at sourceware dot org
Reporter: abhay at sourceware dot org
Target Milestone: ---
On ppc64le, the "compile" command generates code that stores a
corrupted address whenever the compiled expression takes the address
of a symbol in the inferior. Calling through such an address makes
the inferior jump to unmapped memory and receive SIGSEGV.
Reproducer (pmf.cc):
struct A { int x; int get (int i); };
int A::get (int i) { return x + i; }
typedef int (A::*PMF) (int);
int main () {
A a; a.x = 5;
PMF pmf = &A::get;
int var = (a.*pmf) (1);
var = 1; /* break here */
return var;
}
$ g++ -g -O0 pmf.cc -o pmf
$ gdb -q -batch \
-ex "break 18" -ex run \
-ex "info address A::get" \
-ex "compile code pmf = &A::get" \
-ex "x/2gx &pmf" \
./pmf
Symbol "A::get(int)" is a function at address 0x1000067c.
0x7fffffffebe8: 0x000080001000067c 0x0000000000000000
Expected: pmf holds 0x000000001000067c.
Actual: pmf holds 0x000080001000067c -- the low 32 bits are
correct but bit 47 is wrongly set. Adding "-ex continue" so the
program calls through pmf gives:
Program received signal SIGSEGV, Segmentation fault.
0x000080001000067c in ?? ()
Analysis:
ppc64_linux_gcc_target_options() returns "", which overrides the
"-mcmodel=large" that default_gcc_target_options() supplies for
64-bit targets, so the injected object is compiled with
-mcmodel=medium. Addresses of inferior symbols are then compiled as
TOC-relative accesses using R_PPC64_TOC16_HA/LO relocations, whose
displacement is a signed 32-bit value (+/- 2GB).
GDB mmaps the compiled module in the high mmap region (e.g. around
0x7ffff7f30000) while the inferior's text is low (e.g. around
0x10000000). The distance between them is close to 2^47, far beyond
the reach of a TOC16 relocation, so the displacement is truncated to
32 bits and the resulting address is off by 2^47.
BFD reports this via the reloc_overflow link callback, but
gdb/compile/compile-object-load.c installs an empty
link_callbacks_reloc_overflow(), so the overflow is discarded and the
truncated bytes are written into the inferior with no diagnostic.
This was introduced by commit 533f04079c7 ("[gdb] [rs6000] Add
ppc64_linux_gcc_target_options method."), which switched ppc64 from
the default large code model to medium.
Compiling the injected code with -mcmodel=large avoids the problem:
GCC then emits a real .toc section and loads addresses as full 64-bit
values, so the only TOC-relative references are into the module's own
.toc, which is always in range. x86-64 is unaffected (no TOC); the
same test stores the correct address there.
In-tree this reproduces as failures in
gdb.compile/compile-cplus-method.exp:
FAIL: gdb.compile/compile-cplus-method.exp: result of compile code \
pmf = &A::get_var1; var = (a->*pmf) (2); pmf = &A::get_var
FAIL: gdb.compile/compile-cplus-method.exp: result of compile code \
(a->**pmf_p) (1)
FAIL: gdb.compile/compile-cplus-method.exp: compile print \
(a->**pmf_p) (1)
Environment: powerpc64le-linux, Fedora, GCC 15.2.1, glibc 2.42.
Reproduced on GDB 18.0.50 (git); also observed across two builds two
months apart and under the distribution's system GDB.
--
You are receiving this mail because:
You are on the CC list for the bug.