cf
https://bugzilla.redhat.com/show_bug.cgi?id=546017#c4
and
http://lists.dwarfstd.org/private.cgi/dwarf-discuss-dwarfstd.org/2009-Dec...
These two things merit lint warnings in the high-level stratum.
1. DW_AT_const_value with a constant form that is actually meant to be an
address constant. This is a problem for consumers, because they expect
that only DW_FORM_addr operands need to be adjusted for PIC addresses,
while constant forms are exact integer constants. Only if the value of
DW_AT_const_value is DW_FORM_addr do we know that we might need to apply
an address adjustment at runtime.
You can detect this in a few ways:
In an ET_REL file, DW_FORM_data[48] with an operand that has a reloc
record. This is an entirely reliable test when you can do it. For
non-ET_REL files, you have to do some less perfect heuristics:
We think it only comes up with the data[48] forms, so you don't need to
try these heuristics with any other forms AFAICT.
If the value lies within some ELF symbol's st_value+st_size range (or
matches st_value exactly, in case of st_size=0), it was probably an
address.
If the DIE with DW_AT_const_value has a DW_AT_type (but use
dwarf_attr_integrate or equivalent for indirections), then if
that refers to a pointer type then it was probably an address.
(You may need to follow levels of typedef and qualifier DIEs to
find the DW_TAG_pointer_type or DW_TAG_reference_type and be sure.)
If either or both of those is true, then it probably was an address that
should have used DW_FORM_addr. OTOH, if it was a pointer type and the
value was 0, then that is probably a constant 0 whether or not any
symbol has st_value=0.
2. In a DWARF expression, DW_OP_addr used with DW_OP_GNU_push_tls_address
or DW_OP_form_tls_address. This is a related problem, with the same
issue for consumers, but the inverse false indication in what old
compilers generate.
The value on the stack before DW_OP_GNU_push_tls_address or
DW_OP_form_tls_address is an offset into the TLS block, not an address.
It doesn't get adjusted for any runtime bias like real addresses do.
So using DW_OP_addr is wrong and should get a warning.
For extra credit, you can test the constant value (either in wrong
DW_OP_addr or right DW_OP_const*/lit*) for sanity. This is really a
separate item and not at all necessary, but extra sanity checks are
always nice wishlist items. In an ET_REL file, the value should always
be one with a reloc record that uses a TLS *OFF reloc type (correct set
of types is machine-dependent and would need a new ebl hook). In other
files, the value should always be inside the p_memsz of the PT_TLS phdr.
Both of these trip up consumers and so should get a suspicious/wrong
warning. However, they both need to be in the quirks table for all extant
GCC versions. We hope to have 4.6 (and 4.[45]-RH) changed to do these two
differently so that DW_{FORM,OP}_addr exactly matches the set of address
constants that require runtime adjustment. But so far all GCC versions
emit the "wrong" patterns described above.
In all cases of DW_{FORM,OP}_addr, an extra check is for matching (having a
reloc pointing to, in ET_REL) an ELF symbol that is actually SHN_ABS. That
is not really the compiler's fault, since it didn't know what strangeness
with linker scripts or hand assembly was going to produce that. But it
will probably cause consumers to apply an adjustment when they shouldn't,
so a warning about it might be nice.
Thanks,
Roland