On Tue, Jun 21, 2011 at 8:09 PM, Drasko DRASKOVIC
<[email protected]> wrote:
> On Tue, Jun 21, 2011 at 7:35 PM, Michael Schwingen
> <[email protected]> wrote:
>> I have no objection against implementing the gdb workaround (checking if
>> *all* sections are zero)
>
> Yes,
> I think that would be the most correct way.

Hi Øyvind,
as per discussion led, please find the patch attached, with
corrections based on Michaels suggestions and deeper study of BFD's
implementation.

Basically, this patch re-implements this peice of code from BFD's elf.c :

 /* Some ELF linkers produce binaries with all the program header
         p_paddr fields zero.  If we have such a binary with more than
         one PT_LOAD header, then leave the section lma equal to vma
         so that we don't create sections with overlapping lma.  */
      phdr = elf_tdata (abfd)->phdr;
      for (nload = 0, i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
        if (phdr->p_paddr != 0)
          break;
        else if (phdr->p_type == PT_LOAD && phdr->p_memsz != 0)
          ++nload;
      if (i >= elf_elfheader (abfd)->e_phnum && nload > 1)
        return TRUE;

which looks if :
1) All (not just one) segments have p_paddr equal to zero (which hints
either p_paddr not initialized or deliberatly initialized to zero,
like some ARM linkers do in otder to repect ARM ELF specification)
2) If this is the case, is there more than one loadable segment
(because we can and we *must* allow one loadable segment at physical
(lma) address 0x0 - this is perfectly valid)
3) If there is however more than one p_paddr zeroed and loadable
segment, we suspect that things are not right and we go for p_vaddr

This will make OpenOCD more conistent to GDB solution and correct the
bug present for ARM ELF compliant linkers.

Best regards,
Drasko
From ee79560a904746536eff2f284c192d45853ebc4a Mon Sep 17 00:00:00 2001
From: Drasko DRASKOVIC <[email protected]>
Date: Wed, 22 Jun 2011 12:45:21 +0200
Subject: [PATCH] Fix load_image for ELF with all p_paddr set to zero

So far image_load command tries to load ELF binaries to address
discovered by reading p_paddr member of a Program header of an ELF
segment.

However, ELF specifications says for p_paddr : ...Because System V
ignores physical addressing for application programs, this member has
unspecified contents for executable files and shared objects.

ARM ELF specifiaction goes even further, demanding that this member
be set to zero, using the p_vaddr as a segment load address.

To avoid the cases to wrong addr where p_paddr is zero,
we are now using p_vaddr to as a load destination in case that *all*
p_paddr == 0. Basically, this patch re-implements the approach present in
BDF's elf.c, which is used by GDB also (so that we can be consistent).
---
 src/target/image.c |   26 +++++++++++++++++++++++++-
 1 files changed, 25 insertions(+), 1 deletions(-)

diff --git a/src/target/image.c b/src/target/image.c
index 454fc6c..21ce11f 100644
--- a/src/target/image.c
+++ b/src/target/image.c
@@ -396,6 +396,7 @@ static int image_elf_read_headers(struct image *image)
 	size_t read_bytes;
 	uint32_t i,j;
 	int retval;
+	uint32_t nload,load_to_vaddr=0;
 
 	elf->header = malloc(sizeof(Elf32_Ehdr));
 
@@ -471,6 +472,26 @@ static int image_elf_read_headers(struct image *image)
 	for (i = 0;i < elf->segment_count;i++)
 		if ((field32(elf, elf->segments[i].p_type) == PT_LOAD) && (field32(elf, elf->segments[i].p_filesz) != 0))
 			image->num_sections++;
+
+	/**
+	 * some ELF linkers produce binaries with *all* the program header
+	 * p_paddr fields zero (there can be however one loadable segment
+	 * that has valid physical address 0x0).
+	 * If we have such a binary with more than
+	 * one PT_LOAD header, then use p_vaddr instead of p_paddr
+	 * (ARM ELF standard demands p_paddr = 0 anyway, and BFD
+	 * library uses this approach to workaround zero-initialized p_paddrs
+	 * when obtaining lma - look at elf.c of BDF)
+	 */
+	for (nload = 0, i = 0; i < elf->segment_count; i++)
+		if (elf->segments[i].p_paddr != 0)
+			break;
+		else if ((field32(elf, elf->segments[i].p_type) == PT_LOAD) && (field32(elf, elf->segments[i].p_memsz) != 0))
+			++nload;
+
+	if (i >= elf->segment_count && nload > 1)
+		load_to_vaddr = 1;
+
 	/* alloc and fill sections array with loadable segments */
 	image->sections = malloc(image->num_sections * sizeof(struct imagesection));
 	for (i = 0,j = 0;i < elf->segment_count;i++)
@@ -478,7 +499,10 @@ static int image_elf_read_headers(struct image *image)
 		if ((field32(elf, elf->segments[i].p_type) == PT_LOAD) && (field32(elf, elf->segments[i].p_filesz) != 0))
 		{
 			image->sections[j].size = field32(elf,elf->segments[i].p_filesz);
-			image->sections[j].base_address = field32(elf,elf->segments[i].p_paddr);
+			if (load_to_vaddr)
+				image->sections[j].base_address = field32(elf,elf->segments[i].p_vaddr);
+			else
+				image->sections[j].base_address = field32(elf,elf->segments[i].p_paddr);
 			image->sections[j].private = &elf->segments[i];
 			image->sections[j].flags = field32(elf,elf->segments[i].p_flags);
 			j++;
-- 
1.5.6.5

_______________________________________________
Openocd-development mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/openocd-development

Reply via email to