This is the mail archive of the mailing list for the binutils 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]

[PATCH] ld: provide __ehdr_start magic symbol

This adds a new linker feature for ELF targets.  It provides
(i.e. defines if referenced) the special symbol "__ehdr_start" to
the place in the address space where the ELF file header appears (if
that's also in the same segment where the program headers appear).
(I also have a patch for gold, which I'll submit separately after
the feature is agreed to and committed for BFD ld.)

This provides a direct way for a program to examine its own headers.
The usual use of this is to look at the program headers, e.g. to find
PT_TLS and use its parameters in TLS initialization.  Today, a program
has to rely on the system program loader to supply the AT_PHDR et al
fields in the auxv.  But it's not possible to rely on that in all
circumstances, and this is something that is statically knowable at
link time, so there's no reason it ought to depend on a runtime feature.

It's also possible to define symbols giving the start and end of the
phdrs image.  But that is inadvisable because of tools that can change
the headers after link time.  For example, prelink will sometimes
insert a new phdr; objcopy can convert an ELFCLASS64 file to an
ELFCLASS32 file, changing the position and size of the phdrs.  In the
usual layouts, where the ehdr and phdrs both appear in the same
PT_LOAD segment, looking at the ehdr to find the phdrs from its
e_phoff field (and verify their size with e_phentsize, etc.) is the
only really robust approach.

I tried to make the definition consistent with the symbols defined
by PROVIDE and similar magic features like __start_*/__stop_*.

It might be possible to define this symbol entirely in the default
linker script.  But I was not confident that there would be a way to
do this that might not wind up defining it incorrectly in some
situation where the headers are not actually visible in the program
image, e.g. under strange combinations of --section-start et al

The __executable_start symbol winds up with the same value as
__ehdr_start in the usual layouts on the most common targets, but it
does not always match up for all targets or all layout details that
might be used (and doesn't exist at all in shared objects).  So I
think the new symbol really is necessary.

I did find anywhere in ld.texinfo that documents the existing
magical symbols like __executable_start, etext, etc.  So I did
not add any mention of this to the manual.

Ok for trunk?


2012-06-19  Roland McGrath  <>

	* elf.c (assign_file_positions_for_non_load_sections): Define
	__ehdr_start symbol if it's referenced and there's a PT_LOAD
	segment that covers both the file and program headers.

2012-06-19  Roland McGrath  <>

	* NEWS: Mention __ehdr_start.

2012-06-19  Roland McGrath  <>

	* ld-elf/ehdr_start.s: New file.
	* ld-elf/ehdr_start.d: New file.

diff --git a/bfd/elf.c b/bfd/elf.c
index 0296ef5..99771f5 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -4826,6 +4826,7 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
   Elf_Internal_Phdr *phdrs;
   Elf_Internal_Phdr *p;
   struct elf_segment_map *m;
+  struct elf_segment_map *hdrs_segment;
   bfd_vma filehdr_vaddr, filehdr_paddr;
   bfd_vma phdrs_vaddr, phdrs_paddr;
   file_ptr off;
@@ -4883,6 +4884,7 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
   filehdr_paddr = 0;
   phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr;
   phdrs_paddr = 0;
+  hdrs_segment = NULL;
   phdrs = elf_tdata (abfd)->phdr;
   for (m = elf_tdata (abfd)->segment_map, p = phdrs;
        m != NULL;
@@ -4903,12 +4905,36 @@ assign_file_positions_for_non_load_sections (bfd *abfd,
 	  phdrs_paddr = p->p_paddr;
 	  if (m->includes_filehdr)
+	      hdrs_segment = m;
 	      phdrs_vaddr += bed->s->sizeof_ehdr;
 	      phdrs_paddr += bed->s->sizeof_ehdr;
+  if (hdrs_segment != NULL && link_info != NULL)
+    {
+      /* There is a segment that contains both the file headers and the
+	 program headers, so provide a symbol __ehdr_start pointing there.
+	 A program can use this to examine itself robustly.  */
+      struct elf_link_hash_entry *hash
+	= elf_link_hash_lookup (elf_hash_table (link_info), "__ehdr_start",
+      if (hash != NULL
+	  && (hash->root.type == bfd_link_hash_new
+	      || hash->root.type == bfd_link_hash_undefined
+	      || hash->root.type == bfd_link_hash_undefweak
+	      || hash->root.type == bfd_link_hash_common))
+	{
+	  hash->root.type = bfd_link_hash_defined;
+	  hash->root.u.def.value = filehdr_vaddr;
+	  hash->root.u.def.section = bfd_abs_section_ptr;
+	  hash->def_regular = 1;
+	  hash->non_elf = 0;
+	}
+    }
   for (m = elf_tdata (abfd)->segment_map, p = phdrs;
        m != NULL;
        m = m->next, p++)
diff --git a/ld/NEWS b/ld/NEWS
index cb2d428..8701c5c 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,9 @@
 -*- text -*-
+* Add a linker-provided symbol when producing ELF output, '__ehdr_start'
+  to point to the ELF file header (and nearby program headers) in the
+  program's memory image.
 * Add support for S12X processor.
 * Add support for the VLE extension to the PowerPC architecture.
diff --git a/ld/testsuite/ld-elf/ehdr_start.d b/ld/testsuite/ld-elf/ehdr_start.d
new file mode 100644
index 0000000..a81577e
--- /dev/null
+++ b/ld/testsuite/ld-elf/ehdr_start.d
@@ -0,0 +1,7 @@
+#source: ehdr_start.s
+#nm: -n
+[0-9a-f]*000 A __ehdr_start
diff --git a/ld/testsuite/ld-elf/ehdr_start.s b/ld/testsuite/ld-elf/ehdr_start.s
new file mode 100644
index 0000000..2086801
--- /dev/null
+++ b/ld/testsuite/ld-elf/ehdr_start.s
@@ -0,0 +1,9 @@
+	.text
+	.globl _start
+	.space 16
+	.section .rodata,"a",%progbits
+	.globl foo
+	.dc.a __ehdr_start

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