version 1.1.1.1, 2008/06/03 10:38:40 |
version 1.1.1.1.2.1, 2008/08/13 17:12:20 |
|
|
#include <sys/elf.h> |
#include <sys/elf.h> |
#include <platform.h> |
#include <platform.h> |
|
|
|
#ifdef DEBUG_ELF |
|
#define DPRINTF(a) printf a |
|
#else |
|
#define DPRINTF(a) do {} while (0) |
|
#endif |
|
|
extern int nr_img; /* number of images */ |
extern int nr_img; /* number of images */ |
|
|
#define SHF_VALID (SHF_ALLOC | SHF_EXECINSTR | SHF_ALLOC | SHF_WRITE) |
#define SHF_VALID (SHF_ALLOC | SHF_EXECINSTR | SHF_ALLOC | SHF_WRITE) |
|
|
{ |
{ |
Elf32_Ehdr *ehdr; |
Elf32_Ehdr *ehdr; |
Elf32_Phdr *phdr; |
Elf32_Phdr *phdr; |
u_long phys_base; |
paddr_t phys_base; |
int i; |
int i; |
|
|
phys_base = load_base; |
phys_base = load_base; |
ehdr = (Elf32_Ehdr *)img; |
ehdr = (Elf32_Ehdr *)img; |
phdr = (Elf32_Phdr *)((u_long)ehdr + ehdr->e_phoff); |
phdr = (Elf32_Phdr *)((paddr_t)ehdr + ehdr->e_phoff); |
m->phys = load_base; |
m->phys = load_base; |
phys_base = load_base; |
phys_base = load_base; |
elf_print("phys addr=%x\n", phys_base); |
DPRINTF(("phys addr=%x\n", phys_base)); |
|
|
for (i = 0; i < (int)ehdr->e_phnum; i++, phdr++) { |
for (i = 0; i < (int)ehdr->e_phnum; i++, phdr++) { |
if (phdr->p_type != PT_LOAD) |
if (phdr->p_type != PT_LOAD) |
continue; |
continue; |
|
|
elf_print("p_flags=%x\n", (int)phdr->p_flags); |
DPRINTF(("p_flags=%x\n", (int)phdr->p_flags)); |
elf_print("p_align=%x\n", (int)phdr->p_align); |
DPRINTF(("p_align=%x\n", (int)phdr->p_align)); |
elf_print("p_paddr=%x\n", (int)phdr->p_paddr); |
DPRINTF(("p_paddr=%x\n", (int)phdr->p_paddr)); |
|
|
if (i >= 2) { |
if (i >= 2) { |
elf_print("skipping extra phdr\n"); |
DPRINTF(("skipping extra phdr\n")); |
continue; |
continue; |
} |
} |
if (phdr->p_flags & PF_X) { |
if (phdr->p_flags & PF_X) { |
|
|
if (phdr->p_filesz > 0) { |
if (phdr->p_filesz > 0) { |
memcpy((char *)load_base, img + phdr->p_offset, |
memcpy((char *)load_base, img + phdr->p_offset, |
(size_t)phdr->p_filesz); |
(size_t)phdr->p_filesz); |
elf_print("load: offset=%x size=%x\n", |
DPRINTF(("load: offset=%x size=%x\n", |
load_base, (int)phdr->p_filesz); |
load_base, (int)phdr->p_filesz)); |
} |
} |
if (!(phdr->p_flags & PF_X)) { |
if (!(phdr->p_flags & PF_X)) { |
if (m->bsssz > 0) { |
if (m->bsssz > 0) { |
|
|
load_base = PAGE_ALIGN(load_base); |
load_base = PAGE_ALIGN(load_base); |
m->size = (size_t)(load_base - m->phys); |
m->size = (size_t)(load_base - m->phys); |
m->entry = ehdr->e_entry; |
m->entry = ehdr->e_entry; |
elf_print("module size=%x entry=%x\n", m->size, m->entry); |
DPRINTF(("module size=%x entry=%x\n", m->size, m->entry)); |
return 0; |
return 0; |
} |
} |
|
|
|
|
if (relocate_rela(rela, sym_val, target_sect) != 0) |
if (relocate_rela(rela, sym_val, target_sect) != 0) |
return -1; |
return -1; |
} else if (ELF32_ST_BIND(sym->st_info) != STB_WEAK) { |
} else if (ELF32_ST_BIND(sym->st_info) != STB_WEAK) { |
printk("Undefined symbol for rela[%x] sym=%x\n", |
DPRINTF(("Undefined symbol for rela[%x] sym=%x\n", |
i, sym); |
i, sym)); |
return -1; |
return -1; |
} else { |
} else { |
elf_print("Undefined weak symbol for rela[%x]\n", i); |
DPRINTF(("Undefined weak symbol for rela[%x]\n", i)); |
} |
} |
rela++; |
rela++; |
} |
} |
|
|
if (relocate_rel(rel, sym_val, target_sect) != 0) |
if (relocate_rel(rel, sym_val, target_sect) != 0) |
return -1; |
return -1; |
} else if (ELF32_ST_BIND(sym->st_info) != STB_WEAK) { |
} else if (ELF32_ST_BIND(sym->st_info) != STB_WEAK) { |
printk("Undefined symbol for rel[%x] sym=%x\n", |
DPRINTF(("Undefined symbol for rel[%x] sym=%x\n", |
i, sym); |
i, sym)); |
return -1; |
return -1; |
} else { |
} else { |
elf_print("Undefined weak symbol for rel[%x]\n", i); |
DPRINTF(("Undefined weak symbol for rel[%x]\n", i)); |
} |
} |
rel++; |
rel++; |
} |
} |
|
|
{ |
{ |
Elf32_Ehdr *ehdr; |
Elf32_Ehdr *ehdr; |
Elf32_Shdr *shdr; |
Elf32_Shdr *shdr; |
u_long sect_base, bss_base; |
paddr_t sect_base, bss_base; |
int i; |
int i; |
|
|
ehdr = (Elf32_Ehdr *)img; |
ehdr = (Elf32_Ehdr *)img; |
shdr = (Elf32_Shdr *)((u_long)ehdr + ehdr->e_shoff); |
shdr = (Elf32_Shdr *)((paddr_t)ehdr + ehdr->e_shoff); |
bss_base = 0; |
bss_base = 0; |
m->phys = load_base; |
m->phys = load_base; |
elf_print("phys addr=%x\n", load_base); |
DPRINTF(("phys addr=%x\n", load_base)); |
|
|
/* Copy sections */ |
/* Copy sections */ |
for (i = 0; i < (int)ehdr->e_shnum; i++, shdr++) { |
for (i = 0; i < (int)ehdr->e_shnum; i++, shdr++) { |
sect_addr[i] = 0; |
sect_addr[i] = 0; |
if (shdr->sh_type == SHT_PROGBITS) { |
if (shdr->sh_type == SHT_PROGBITS) { |
|
|
elf_print("sh_addr=%x\n", shdr->sh_addr); |
DPRINTF(("sh_addr=%x\n", shdr->sh_addr)); |
elf_print("sh_size=%x\n", shdr->sh_size); |
DPRINTF(("sh_size=%x\n", shdr->sh_size)); |
elf_print("sh_offset=%x\n", shdr->sh_offset); |
DPRINTF(("sh_offset=%x\n", shdr->sh_offset)); |
elf_print("sh_flags=%x\n", shdr->sh_flags); |
DPRINTF(("sh_flags=%x\n", shdr->sh_flags)); |
|
|
switch (shdr->sh_flags & SHF_VALID) { |
switch (shdr->sh_flags & SHF_VALID) { |
case (SHF_ALLOC | SHF_EXECINSTR): |
case (SHF_ALLOC | SHF_EXECINSTR): |
/* Text */ |
/* Text */ |
m->text = (u_long)phys_to_virt(load_base); |
m->text = (vaddr_t)phys_to_virt(load_base); |
break; |
break; |
case (SHF_ALLOC | SHF_WRITE): |
case (SHF_ALLOC | SHF_WRITE): |
/* Data */ |
/* Data */ |
if (m->data == 0) |
if (m->data == 0) |
m->data = |
m->data = |
(u_long)phys_to_virt(load_base + shdr->sh_addr); |
(vaddr_t)phys_to_virt(load_base + shdr->sh_addr); |
break; |
break; |
case SHF_ALLOC: |
case SHF_ALLOC: |
/* rodata */ |
/* rodata */ |
|
|
sect_base = load_base + shdr->sh_addr; |
sect_base = load_base + shdr->sh_addr; |
memcpy((char *)sect_base, img + shdr->sh_offset, |
memcpy((char *)sect_base, img + shdr->sh_offset, |
(size_t)shdr->sh_size); |
(size_t)shdr->sh_size); |
elf_print("load: offset=%x size=%x\n", |
DPRINTF(("load: offset=%x size=%x\n", |
sect_base, (int)shdr->sh_size); |
sect_base, (int)shdr->sh_size)); |
|
|
sect_addr[i] = (char *)sect_base; |
sect_addr[i] = (char *)sect_base; |
} else if (shdr->sh_type == SHT_NOBITS) { |
} else if (shdr->sh_type == SHT_NOBITS) { |
|
|
load_base = bss_base + m->bsssz; |
load_base = bss_base + m->bsssz; |
load_base = PAGE_ALIGN(load_base); |
load_base = PAGE_ALIGN(load_base); |
|
|
elf_print("module load_base=%x text=%x\n", load_base, m->text); |
DPRINTF(("module load_base=%x text=%x\n", load_base, m->text)); |
m->size = (size_t)(load_base - (u_long)virt_to_phys(m->text)); |
m->size = (size_t)(load_base - (paddr_t)virt_to_phys(m->text)); |
m->entry = (u_long)phys_to_virt(ehdr->e_entry + m->phys); |
m->entry = (vaddr_t)phys_to_virt(ehdr->e_entry + m->phys); |
elf_print("module size=%x entry=%x\n", m->size, m->entry); |
DPRINTF(("module size=%x entry=%x\n", m->size, m->entry)); |
|
|
/* Process relocation */ |
/* Process relocation */ |
shdr = (Elf32_Shdr *)((u_long)ehdr + ehdr->e_shoff); |
shdr = (Elf32_Shdr *)((paddr_t)ehdr + ehdr->e_shoff); |
for (i = 0; i < (int)ehdr->e_shnum; i++, shdr++) { |
for (i = 0; i < (int)ehdr->e_shnum; i++, shdr++) { |
if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) { |
if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) { |
if (relocate_section(img, shdr) != 0) |
if (relocate_section(img, shdr) != 0) |
|
|
Elf32_Ehdr *ehdr; |
Elf32_Ehdr *ehdr; |
Elf32_Phdr *phdr; |
Elf32_Phdr *phdr; |
|
|
elf_print("\nelf_load\n"); |
DPRINTF(("\nelf_load\n")); |
|
|
ehdr = (Elf32_Ehdr *)img; |
ehdr = (Elf32_Ehdr *)img; |
|
|
|
|
(ehdr->e_ident[EI_MAG3] != ELFMAG3)) |
(ehdr->e_ident[EI_MAG3] != ELFMAG3)) |
return -1; |
return -1; |
|
|
phdr = (Elf32_Phdr *)((u_long)ehdr + ehdr->e_ehsize); |
phdr = (Elf32_Phdr *)((paddr_t)ehdr + ehdr->e_ehsize); |
|
|
if (nr_img == 0) { |
if (nr_img == 0) { |
/* Initialize the load address */ |
/* Initialize the load address */ |
load_base = (u_long)phys_to_virt(phdr->p_paddr); |
load_base = (vaddr_t)phys_to_virt(phdr->p_paddr); |
if (load_base == 0) |
if (load_base == 0) |
return -1; |
return -1; |
elf_print("kernel base=%x\n", load_base); |
DPRINTF(("kernel base=%x\n", load_base)); |
load_start = load_base; |
load_start = load_base; |
} |
} |
else if (nr_img == 1) { |
else if (nr_img == 1) { |
/* Second image => Driver */ |
/* Second image => Driver */ |
elf_print("driver base=%x\n", load_base); |
DPRINTF(("driver base=%x\n", load_base)); |
} |
} |
else { |
else { |
/* Other images => Boot tasks */ |
/* Other images => Boot tasks */ |
elf_print("task base=%x\n", load_base); |
DPRINTF(("task base=%x\n", load_base)); |
} |
} |
|
|
switch (ehdr->e_type) { |
switch (ehdr->e_type) { |
|
|
return -1; |
return -1; |
break; |
break; |
default: |
default: |
elf_print("Unsupported file type\n"); |
DPRINTF(("Unsupported file type\n")); |
return -1; |
return -1; |
} |
} |
nr_img++; |
nr_img++; |