|
From: John R. <jr...@bi...> - 2013-06-05 15:45:09
|
On 06/04/2013, Britton Kerin wrote about "Beagleboard white" ARM using Angstrom Linux:
>>> root@bboneumh2:~/software# ~/local/bin/valgrind --leak-check=yes
>>> ./clock_gettime CLOCK_MONOTONIC
>>> ==28151== Memcheck, a memory error detector
>>> ==28151== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
>>> ==28151== Using Valgrind-3.9.0.SVN and LibVEX; rerun with -h for copyright info
>>> ==28151== Command: ./clock_gettime CLOCK_MONOTONIC
>>> ==28151==
>>> ==28151== Conditional jump or move depends on uninitialised value(s)
>>> ==28151== at 0x400B308: ??? (in /lib/ld-2.12.2.so)
>>> ==28151==
> I'll attach the output of 'objdump -d -S /lib/ld-2.12.2.so' as well. In
> case I'm misunderstanding things.
The addresses such as
==28151== at 0x400B308: ??? (in /lib/ld-2.12.2.so)
are "in /lib/ld-2.12.2.so", so the code at that location is what matters.
Looking at those addresses (0x4000000 less because of runtime placement
in the process versus no prelinking in the file):
$$$ b1b4: e0828001 add r8, r2, r1
b1b8: e5970008 ldr r0, [r7, #8]
b1bc: e3500000 cmp r0, #0
%%% b1c0: 0a00011f beq b644 <_dl_rtld_di_serinfo+0x2fbc>
b1c4: e1520008 cmp r2, r8
%%% b1c8: 2a00000d bcs b204 <_dl_rtld_di_serinfo+0x2b7c>
b2bc: e30a0aab movw r0, #43691 ; 0xaaab
b2c0: e595c004 ldr ip, [r5, #4]
b2c4: e34a0aaa movt r0, #43690 ; 0xaaaa; 0xaaaaaaab = (2<<32)/3
b2c8: e0815190 umull r5, r1, r0, r1 ### (r5=hi, r1=lo) = r0 * r1; 32x32==>64
b2cc: e1a011a1 lsr r1, r1, #3 ### r1 = original_r1 / 12;
b2d0: e151000c cmp r1, ip
b2d4: 21a0100c movcs r1, ip ### minimum
b2d8: e0811081 add r1, r1, r1, lsl #1 ### r1 = r1 + (r1<<1); // * 3
b2dc: e1a05101 lsl r5, r1, #2
b2e0: e51b7070 ldr r7, [fp, #-112] ; 0x70
$$$ b2e4: e0825005 add r5, r2, r5
b2e8: e08f1007 add r1, pc, r7
b2ec: e2811e51 add r1, r1, #1296 ; 0x510
b2f0: e2811008 add r1, r1, #8
b2f4: e1540001 cmp r4, r1
b2f8: 0a00000a beq b328 <_dl_rtld_di_serinfo+0x2ca0>
b2fc: e35a0000 cmp sl, #0
b300: 0a000239 beq bbec <_dl_rtld_di_serinfo+0x3564>
b304: e1520005 cmp r2, r5
%%% b308: 2a000006 bcs b328 <_dl_rtld_di_serinfo+0x2ca0>
b30c: e5931008 ldr r1, [r3, #8]
b310: e5932000 ldr r2, [r3]
b314: e283300c add r3, r3, #12
b318: e1550003 cmp r5, r3
b31c: e081100a add r1, r1, sl
b320: e782100a str r1, [r2, sl]
b324: 8afffff8 bhi b30c <_dl_rtld_di_serinfo+0x2c84>
b328: e59430e4 ldr r3, [r4, #228] ; 0xe4
b32c: e3530000 cmp r3, #0
b330: 0a000362 beq c0c0 <_dl_rtld_di_serinfo+0x3a38>
b334: e51b0064 ldr r0, [fp, #-100] ; 0x64
b338: e5933004 ldr r3, [r3, #4]
b33c: e1500005 cmp r0, r5
b340: e50b3068 str r3, [fp, #-104] ; 0x68
%%% b344: 9a000088 bls b56c <_dl_rtld_di_serinfo+0x2ee4>
c0c0: e51bc064 ldr ip, [fp, #-100] ; 0x64
c0c4: e15c0005 cmp ip, r5
%%% c0c8: 9afffd27 bls b56c <_dl_rtld_di_serinfo+0x2ee4>
we see that the complaints are about comparisons such as
b1c4: e1520008 cmp r2, r8
b304: e1520005 cmp r2, r5
where one of the operands was an addend for the other:
$$$ b1b4: e0828001 add r8, r2, r1 ### r8 = r2 + r1;
$$$ b2e4: e0825005 add r5, r2, r5 ### r5 += r2;
This looks like [I saw this a decade ago]:
----- glibc-2.12/elf/do-rel.h
auto inline void __attribute__ ((always_inline))
elf_dynamic_do_rel (struct link_map *map,
ElfW(Addr) reladdr, ElfW(Addr) relsize,
int lazy)
{
const ElfW(Rel) *r = (const void *) reladdr;
const ElfW(Rel) *end = (const void *) (reladdr + relsize);
ElfW(Addr) l_addr = map->l_addr;
#if (!defined DO_RELA || !defined ELF_MACHINE_PLT_REL) && !defined RTLD_BOOTSTRAP
/* We never bind lazily during ld.so bootstrap. Unfortunately gcc is
not clever enough to see through all the function calls to realize
that. */
if (lazy)
{
/* Doing lazy PLT relocations; they need very little info. */
for (; r < end; ++r)
elf_machine_lazy_rel (map, l_addr, r);
}
-----
----- glibc-2.12/elf/dynamic-link.h
# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \
do { \
struct { ElfW(Addr) start, size; int lazy; } ranges[2]; \
ranges[0].lazy = 0; \
ranges[0].size = ranges[1].size = 0; \
ranges[0].start = 0; \
...
{ \
int ranges_index; \
for (ranges_index = 0; ranges_index < 2; ++ranges_index) \
elf_dynamic_do_##reloc ((map), \
ranges[ranges_index].start, \
ranges[ranges_index].size, \
ranges[ranges_index].lazy); \
} \
-----
Note that ranges[1].start never is initialized in dynamic-link.h,
while elf_dynamic_do_rel() computes the sum
const ElfW(Rel) *r = (const void *) reladdr;
const ElfW(Rel) *end = (const void *) (reladdr + relsize);
and then compares
for (; r < end; ++r)
which relies on
(uninit + 0) == the_same_uninit
Thus glibc violates the C standard, because an operation on an uninitialized
value is totally undefined. Memcheck complains correctly; glibc stubbornly
HAS REFUSED (!!!!!) the trivial fix "ranges[1].start = 0;" which costs *1* CPU cycle.
Glibc uses this code on all platforms, so why doesn't memcheck complain everywhere?
Actually memcheck does notice, but the default suppressions hide the complaint.
Why don't the default suppressions work here?
File valgrind/glibc-2.X.supp contains various suppressions such as:
{
dl-hack3-cond-0
Memcheck:Cond
fun:_dl_start
fun:_start
}
{
dl-hack3-cond-1
Memcheck:Cond
obj:*/lib*/ld-2.12*.so*
obj:*/lib*/ld-2.12*.so*
obj:*/lib*/ld-2.12*.so*
}
which suppress "Cond" complaints ("Conditional jump or move depends on uninitialised value(s)")
in the context of a particular traceback (_dl_start called from _start) or a pattern
of any three nested routines within ld-2.12*.so*.
THE PROBLEM with Angstrom ld-2.12.2.so is that there are so few symbols
that the traceback is only the *one* routine
==28151== at 0x400B308: ??? (in /lib/ld-2.12.2.so)
whose name memcheck does not know. [The only name that objdump discovers is
_dl_rtld_di_serinfo, which is highly suspect.] Thus the known suppressions
do not match the traceback.
Therefore Angstrom should provide better debugging info for developers.
[And glibc should fix its outright error.]
--
|