This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: relocation of DW_AT_low_pc against non-exec and/or non-alloc section


> One of the modules was this one:
> ./i586/gr/ub/grub2-debuginfo-1.98-0.5.20080827svn.fc11.i586/usr/lib/debug/usr/lib/grub2/i386-pc/sleep.mod.debug.bz2
> 
> And the relevant message from my locally hacked version:
> warning: .rel.debug_info: offset 0x50b: associated section #13 isn't 
> SHF_ALLOC.

That's:

 <compile_unit offset=[0x4f9] producer="GNU C 4.4.0 20090219 (Red Hat 4.4.0-0.21)" language=C89 name="mod-sleep.c" comp_dir="/usr/src/debug/grub2" low_pc=0x150 high_pc=0x7 stmt_list=0xaf>
  ...nothing but <base_type>s...
 </compile_unit>

The relocs for the low_pc and high_pc values are:

  0x00000507  386_32               0000000000  .text
  0x0000050b  386_32               0000000000  .moddeps

I looked into the grub2 build.  This boils down to a source file equivalent to:

	typedef int blah;
	__asm__ (".section .modname\n.string \"" "foo" "\"\n");
	__asm__ (".section .moddeps\n.string \"" "bar" "\"\n");

So, this CU and all it produced being associated with a non-SHF_ALLOC
section is kosher enough.  Without some decl like the typedef, it doesn't
produce the CU at all.  I guess it decided it needed a CU because there
were decls at all, but then pruned all the unused types.  (Personally, I
like producing a CU anyway even if it has no children at all--even for
compiling /dev/null.  You compiled the source file, so that's CU
information even if nothing but name, comp_dir, language, producer.)

Since this CU contains only data, it really is fine that it's all in some
specially-named non-allocated sections.  That sort of thing is to be
expected with anything like this using its own module loading relocation
magic.  But indeed no DW_FORM_addr or equivalent really ought to refer to
any non-allocated section.  It seems far less likely that a code section
would be marked non-alloc.

Aside from any SHF_ALLOC check, this pair should be flagged because they
are in two different sections.  (I think I mentioned this before.)  For not
only low_pc+high_pc, but any begin+end pair in other header formats and
whatnot that can have relocs, if either begin or end is relocated, it's
bogus if its mate is not relocated against the same section.

The trouble comes from this part of the output:

gcc		.text
gcc	.Ltext0:
gcc	#APP
asm1		.section .modname
asm1	.string "foo"
asm1
asm2		.section .moddeps
asm2	.string "bar"
asm2
gcc	.Letext0:

Then it uses .Ltext0 and .Letext0 in emitting .debug_info contents later.
This is arguably the fault of the asm not using .pushsection/.popsection or
whatnot.  But my feeling is that it would be best to emit .Ltext0 only
along with the first .text entry label, and .Letext0 only along with the
last .text post-epilogue (.size et al).  (That is how it does the labels
for an alternate section when a function has __attribute__((section("foo"))).)

But there are further problems.  Consider:

	static const char name[] __attribute__ ((section (".modname"))) = "foo";
	static const char deps[] __attribute__ ((section (".moddeps"))) = "bar";

This produces:

	       .text
	.Ltext0:
		.section        .modname,"a",@progbits
		.type   name, @object
		.size   name, 4
	name:
		.string "foo"
		.section        .moddeps,"a",@progbits
		.type   deps, @object
		.size   deps, 4
	deps:
		.string "bar"
		.text
	.Letext0:

as you would expect.  And of course, the CU is useful since it describes
"name" and "deps" and their types.  But it gets a low_pc and high_pc of:

  0x0000000000000015  X86_64_64       000000000000000000      +0 .text
  0x000000000000001d  X86_64_64       000000000000000000      +0 .text

That is harmless enough, but I think it would be better just to omit the
low_pc and high_pc attributes when there are no PC addresses to talk about.

Now, worse:

	static const char name[] __attribute__ ((section (".modname"))) = "foo";
	static const char deps[] __attribute__ ((section (".moddeps"))) = "bar";
	void __attribute__ ((section (".foo"))) foo (void) {}

This produces:

Relocation section [19] '.rela.debug_ranges' for section [18] '.debug_ranges' at offset 0xf08 contains 4 entries:
  Offset              Type            Value               Addend Name
  000000000000000000  X86_64_64       000000000000000000      +0 .text
  0x0000000000000008  X86_64_64       000000000000000000      +0 .text
  0x0000000000000010  X86_64_64       000000000000000000      +0 .foo
  0x0000000000000018  X86_64_64       000000000000000000      +6 .foo

i.e., a spurious empty range in the discontiguous ranges.  
(But not in .debug_aranges!)  Clearly here it should just omit the .Ltext0,
.Letext0 entry.  And in this case there is only one section actually used
by PCs, so it can then drop back to just using low_pc/high_pc instead of
the ranges attribute.

Finally (not a DWARF issue), take:

	typedef int blah;
	void __attribute__ ((section (".foo"))) foo (void) {}
	__asm__ (".section .modname\n.string \"" "foo" "\"\n");
	__asm__ (".section .moddeps\n.string \"" "bar" "\"\n");
	void __attribute__ ((section (".foo"))) bar (void) {}

This produces:

	       .text
	.Ltext0:
		.section        .foo,"ax",@progbits
	.globl foo
		.type   foo, @function
	foo:
	.LFB0:
...
	.LFE0:
		.size   foo, .-foo
	#APP
		.section .modname
	.string "foo"

		.section .moddeps
	.string "bar"

	#NO_APP
	.globl bar
		.type   bar, @function
	bar:
	.LFB1:
...
	.LFE1:
		.size   bar, .-bar
		.text
	.Letext0:

So that actually puts bar into the wrong section.  Again, I don't really
mind at all calling this the fault of the asm-writer.  But it does speak to
the robustness of close-binding things, i.e. emit fresh .section before
each entry (only bother if there was any #APP, I guess), and emit all
labels close-by like .LF[BE][01] here rather than like .L{,e}text0.

Also note that here it emits separate .debug_ranges and .debug_aranges
entries for the foo range and the bar range, even though (modulo the
wrong-section snafu) it knows they are together in a contiguous range,
possibly modulo harmless alignment (though I see no .align here on x86).
We'll make the compressor coalesce those adjacent ranges I guess, but it
seems like it should be simple enough for the compiler to notice in the
first place.


Thanks,
Roland

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]