Roland McGrath wrote:
In this file: kernel-debuginfo-2.6.29-0.258.rc8.git2.fc11.i586:usr:lib:debug:lib:modules:2.6.29-0.258.rc8.git2.fc11.i586:vmlinux
This is not an ET_REL file. It's a final link that uses --emit-relocs. The DWARF data (and all the rest) is fully relocated already.
The kernel build uses --emit-relocs for the benefit of some post-processing that turns the relocs (for allocated sections) into one big table used at runtime to do simple in-place adjustments. (Though the kernel binary is ET_EXEC, basically it acts as if it were an ET_DYN with DT_TEXTREL and all its relocs being just R_386_RELATIVE.)
To start with, it is probably fine not to even look for relocs in files that are not ET_REL. Whatever relocs they have are "extra information" and not really needed to make sense of the DWARF data. (But I'll continue with the details of interpreting this data, in case we want to do the extra checking just because.)
I'm seeing relocations that seem wrong: the addend and the value of the symbol the relocation is done against are the same.
These are SHT_REL, not SHT_RELA. It doesn't have an addend, it only has an in-place value. When relocation still has to be done (as in an ET_REL), the value in place acts as the addend (i.e. symbol value applied with +=). When relocation has already been done, obviously this cannot be so. The final value is in place, and any original nonzero "addend" is lost.
This is why prelink converts SHT_REL to SHT_RELA, btw. In prelink cases, the symbol is usually an undefined external. Hence it has no way to figure out the "original" symbol value added to the original "addend" in place.
Here we always have the original symbol value. We can "derelocate" the in-place value by subtracting the symbol value to recover the lost addend.
Is this useful for anything?
In normal non-ET_REL files, the relocs left in allocated sections are those in the dynamic relocs. That is, SHT_REL{,A} sections that are SHF_ALLOC themselves. Those are "normal" relocs, i.e. that have not been applied yet so in-place values are just the addends (in SHT_REL).
I suppose if someone used --emit-relocs in a normal dynamic link of an executable or DSO, there might be both a dynamic reloc (in an SHT_REL,SHF_ALLOC section) and a preserved reloc (in an SHT_REL,~SHF_ALLOC reloc section) pointing to the same location in an allocated section. But nobody does that. Moreover, in dwarflint we are only checking the relocs that apply to non-allocated sections. For all those, it is unambiguous that the relocs have already been applied to the non-allocated section data.
Eventually we might want to be checking .eh_frame, the only allocated section containing a DWARFish format. In the outlying cases of pure theory, .eh_frame could have dynamic relocs and have this ambiguity if it also has --emit-relocs relocs. But,
- the compiler is always smart enough to emit .eh_frame for PIC without TEXTREL
- nobody really uses --emit-relocs with this
- we will not be touching .eh_frame with the DWARF writer, it's an allocated section--so dwarflint checks on it are not crucial for our correctness checking (just for verifying against gcc/as/ld bugs)
- we might decide to touch/rewrite .eh_frame in the DWARF writer, but would do so only in ET_REL files where this is all moot
One day #2 will probably stop being true in the kernel, because it will start to have .eh_frame itself. But it is statically linked with --emit-relocs and never produces dynamic relocs, so again there is no ambiguity.
So, the "more than complete enough" checking plan (i.e. where you bother with reloc checks in non-ET_REL at all) would be as follows. For a reloc in an SHT_REL (not SHT_RELA) section in a non-ET_REL file, subtract the symbol value (and barf if it's SHN_UNDEF)--note that since it's an ET_REL,
(non-ET_REL I assume)
the st_value is the final value directly, not section-relative. If there is an SHT_REL,SHF_ALLOC section that applies to the section you are checking, complain and punt (however you would if all its relocs were unknown types or whatnot). (If the SHT_REL,SHF_ALLOC section has a target section that is not SHF_ALLOC, elflint should complain about that.)
At this time, dwarflint gives an error if ET_REL file misses a relocation, but does relocation even in non-ET_REL files, if they are present. According to what you say, it should instead ignore relocation sections in non-ET_REL files.
Now what about DW_OP_call_ref, and others that Dwarf3 document claims to be "relocatable in a relocatable object file, and relocated in an executable or shared object"? These are basically the reason why I never had any doubts that I should handle relocations in non-ET_REL files.
Alan Modra's advice (from Jan's email, ignoring relocs that use normal symbol table) seems reasonable to me.
PM