|
@@ -68,28 +68,45 @@ static void elfN(search_symtab)(ElfN(Shdr) *shdr, unsigned sym_idx,
|
|
void *buf, bool need_bswap)
|
|
void *buf, bool need_bswap)
|
|
{
|
|
{
|
|
unsigned str_idx = shdr[sym_idx].sh_link;
|
|
unsigned str_idx = shdr[sym_idx].sh_link;
|
|
- ElfN(Sym) *sym = buf + shdr[sym_idx].sh_offset;
|
|
|
|
- unsigned sym_n = shdr[sym_idx].sh_size / sizeof(*sym);
|
|
|
|
|
|
+ ElfN(Sym) *target_sym = buf + shdr[sym_idx].sh_offset;
|
|
|
|
+ unsigned sym_n = shdr[sym_idx].sh_size / sizeof(*target_sym);
|
|
const char *str = buf + shdr[str_idx].sh_offset;
|
|
const char *str = buf + shdr[str_idx].sh_offset;
|
|
|
|
|
|
for (unsigned i = 0; i < sym_n; ++i) {
|
|
for (unsigned i = 0; i < sym_n; ++i) {
|
|
const char *name;
|
|
const char *name;
|
|
|
|
+ ElfN(Sym) sym;
|
|
|
|
|
|
|
|
+ memcpy(&sym, &target_sym[i], sizeof(sym));
|
|
if (need_bswap) {
|
|
if (need_bswap) {
|
|
- elfN(bswap_sym)(sym + i);
|
|
|
|
|
|
+ elfN(bswap_sym)(&sym);
|
|
}
|
|
}
|
|
- name = str + sym[i].st_name;
|
|
|
|
|
|
+ name = str + sym.st_name;
|
|
|
|
|
|
if (sigreturn_sym && strcmp(sigreturn_sym, name) == 0) {
|
|
if (sigreturn_sym && strcmp(sigreturn_sym, name) == 0) {
|
|
- sigreturn_addr = sym[i].st_value;
|
|
|
|
|
|
+ sigreturn_addr = sym.st_value;
|
|
}
|
|
}
|
|
if (rt_sigreturn_sym && strcmp(rt_sigreturn_sym, name) == 0) {
|
|
if (rt_sigreturn_sym && strcmp(rt_sigreturn_sym, name) == 0) {
|
|
- rt_sigreturn_addr = sym[i].st_value;
|
|
|
|
|
|
+ rt_sigreturn_addr = sym.st_value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static void elfN(process)(FILE *outf, void *buf, bool need_bswap)
|
|
|
|
|
|
+static void elfN(bswap_ps_hdrs)(ElfN(Ehdr) *ehdr)
|
|
|
|
+{
|
|
|
|
+ ElfN(Phdr) *phdr = (void *)ehdr + ehdr->e_phoff;
|
|
|
|
+ ElfN(Shdr) *shdr = (void *)ehdr + ehdr->e_shoff;
|
|
|
|
+ ElfN(Half) i;
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < ehdr->e_phnum; ++i) {
|
|
|
|
+ elfN(bswap_phdr)(&phdr[i]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < ehdr->e_shnum; ++i) {
|
|
|
|
+ elfN(bswap_shdr)(&shdr[i]);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void elfN(process)(FILE *outf, void *buf, long len, bool need_bswap)
|
|
{
|
|
{
|
|
ElfN(Ehdr) *ehdr = buf;
|
|
ElfN(Ehdr) *ehdr = buf;
|
|
ElfN(Phdr) *phdr;
|
|
ElfN(Phdr) *phdr;
|
|
@@ -103,24 +120,14 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap)
|
|
int errors = 0;
|
|
int errors = 0;
|
|
|
|
|
|
if (need_bswap) {
|
|
if (need_bswap) {
|
|
- elfN(bswap_ehdr)(ehdr);
|
|
|
|
|
|
+ elfN(bswap_ehdr)(buf);
|
|
|
|
+ elfN(bswap_ps_hdrs)(buf);
|
|
}
|
|
}
|
|
|
|
|
|
phnum = ehdr->e_phnum;
|
|
phnum = ehdr->e_phnum;
|
|
phdr = buf + ehdr->e_phoff;
|
|
phdr = buf + ehdr->e_phoff;
|
|
- if (need_bswap) {
|
|
|
|
- for (unsigned i = 0; i < phnum; ++i) {
|
|
|
|
- elfN(bswap_phdr)(phdr + i);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
shnum = ehdr->e_shnum;
|
|
shnum = ehdr->e_shnum;
|
|
shdr = buf + ehdr->e_shoff;
|
|
shdr = buf + ehdr->e_shoff;
|
|
- if (need_bswap) {
|
|
|
|
- for (unsigned i = 0; i < shnum; ++i) {
|
|
|
|
- elfN(bswap_shdr)(shdr + i);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
for (unsigned i = 0; i < shnum; ++i) {
|
|
for (unsigned i = 0; i < shnum; ++i) {
|
|
switch (shdr[i].sh_type) {
|
|
switch (shdr[i].sh_type) {
|
|
case SHT_SYMTAB:
|
|
case SHT_SYMTAB:
|
|
@@ -154,7 +161,24 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap)
|
|
fprintf(stderr, "LOAD segment not loaded at address 0\n");
|
|
fprintf(stderr, "LOAD segment not loaded at address 0\n");
|
|
errors++;
|
|
errors++;
|
|
}
|
|
}
|
|
- first_segsz = phdr[i].p_filesz;
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Extend the program header to cover the entire VDSO, so that
|
|
|
|
+ * load_elf_vdso() loads everything, including section headers.
|
|
|
|
+ *
|
|
|
|
+ * Require that there is no .bss, since it would break this
|
|
|
|
+ * approach.
|
|
|
|
+ */
|
|
|
|
+ if (phdr[i].p_filesz != phdr[i].p_memsz) {
|
|
|
|
+ fprintf(stderr, "LOAD segment's filesz and memsz differ\n");
|
|
|
|
+ errors++;
|
|
|
|
+ }
|
|
|
|
+ if (phdr[i].p_filesz > len) {
|
|
|
|
+ fprintf(stderr, "LOAD segment is larger than the whole VDSO\n");
|
|
|
|
+ errors++;
|
|
|
|
+ }
|
|
|
|
+ phdr[i].p_filesz = len;
|
|
|
|
+ phdr[i].p_memsz = len;
|
|
|
|
+ first_segsz = len;
|
|
if (first_segsz < ehdr->e_phoff + phnum * sizeof(*phdr)) {
|
|
if (first_segsz < ehdr->e_phoff + phnum * sizeof(*phdr)) {
|
|
fprintf(stderr, "LOAD segment does not cover PHDRs\n");
|
|
fprintf(stderr, "LOAD segment does not cover PHDRs\n");
|
|
errors++;
|
|
errors++;
|
|
@@ -197,17 +221,24 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap)
|
|
output_reloc(outf, buf, &phdr[i].p_paddr);
|
|
output_reloc(outf, buf, &phdr[i].p_paddr);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* Relocate the section headers. */
|
|
|
|
+ for (unsigned i = 0; i < shnum; ++i) {
|
|
|
|
+ output_reloc(outf, buf, &shdr[i].sh_addr);
|
|
|
|
+ }
|
|
|
|
+
|
|
/* Relocate the DYNAMIC entries. */
|
|
/* Relocate the DYNAMIC entries. */
|
|
if (dynamic_addr) {
|
|
if (dynamic_addr) {
|
|
- ElfN(Dyn) *dyn = buf + dynamic_ofs;
|
|
|
|
- __typeof(dyn->d_tag) tag;
|
|
|
|
|
|
+ ElfN(Dyn) *target_dyn = buf + dynamic_ofs;
|
|
|
|
+ __typeof(((ElfN(Dyn) *)target_dyn)->d_tag) tag;
|
|
|
|
|
|
do {
|
|
do {
|
|
|
|
+ ElfN(Dyn) dyn;
|
|
|
|
|
|
|
|
+ memcpy(&dyn, target_dyn, sizeof(dyn));
|
|
if (need_bswap) {
|
|
if (need_bswap) {
|
|
- elfN(bswap_dyn)(dyn);
|
|
|
|
|
|
+ elfN(bswap_dyn)(&dyn);
|
|
}
|
|
}
|
|
- tag = dyn->d_tag;
|
|
|
|
|
|
+ tag = dyn.d_tag;
|
|
|
|
|
|
switch (tag) {
|
|
switch (tag) {
|
|
case DT_HASH:
|
|
case DT_HASH:
|
|
@@ -218,7 +249,7 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap)
|
|
case DT_PLTGOT:
|
|
case DT_PLTGOT:
|
|
case DT_ADDRRNGLO ... DT_ADDRRNGHI:
|
|
case DT_ADDRRNGLO ... DT_ADDRRNGHI:
|
|
/* These entries store an address in the entry. */
|
|
/* These entries store an address in the entry. */
|
|
- output_reloc(outf, buf, &dyn->d_un.d_val);
|
|
|
|
|
|
+ output_reloc(outf, buf, &target_dyn->d_un.d_val);
|
|
break;
|
|
break;
|
|
|
|
|
|
case DT_NULL:
|
|
case DT_NULL:
|
|
@@ -235,7 +266,7 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap)
|
|
break;
|
|
break;
|
|
|
|
|
|
case DT_SYMENT:
|
|
case DT_SYMENT:
|
|
- if (dyn->d_un.d_val != sizeof(ElfN(Sym))) {
|
|
|
|
|
|
+ if (dyn.d_un.d_val != sizeof(ElfN(Sym))) {
|
|
fprintf(stderr, "VDSO has incorrect dynamic symbol size\n");
|
|
fprintf(stderr, "VDSO has incorrect dynamic symbol size\n");
|
|
errors++;
|
|
errors++;
|
|
}
|
|
}
|
|
@@ -251,7 +282,7 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap)
|
|
* ??? The RISC-V toolchain will emit these even when there
|
|
* ??? The RISC-V toolchain will emit these even when there
|
|
* are no relocations. Validate zeros.
|
|
* are no relocations. Validate zeros.
|
|
*/
|
|
*/
|
|
- if (dyn->d_un.d_val != 0) {
|
|
|
|
|
|
+ if (dyn.d_un.d_val != 0) {
|
|
fprintf(stderr, "VDSO has dynamic relocations\n");
|
|
fprintf(stderr, "VDSO has dynamic relocations\n");
|
|
errors++;
|
|
errors++;
|
|
}
|
|
}
|
|
@@ -287,7 +318,7 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap)
|
|
errors++;
|
|
errors++;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
- dyn++;
|
|
|
|
|
|
+ target_dyn++;
|
|
} while (tag != DT_NULL);
|
|
} while (tag != DT_NULL);
|
|
if (errors) {
|
|
if (errors) {
|
|
exit(EXIT_FAILURE);
|
|
exit(EXIT_FAILURE);
|
|
@@ -296,11 +327,11 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap)
|
|
|
|
|
|
/* Relocate the dynamic symbol table. */
|
|
/* Relocate the dynamic symbol table. */
|
|
if (dynsym_idx) {
|
|
if (dynsym_idx) {
|
|
- ElfN(Sym) *sym = buf + shdr[dynsym_idx].sh_offset;
|
|
|
|
- unsigned sym_n = shdr[dynsym_idx].sh_size / sizeof(*sym);
|
|
|
|
|
|
+ ElfN(Sym) *target_sym = buf + shdr[dynsym_idx].sh_offset;
|
|
|
|
+ unsigned sym_n = shdr[dynsym_idx].sh_size / sizeof(*target_sym);
|
|
|
|
|
|
for (unsigned i = 0; i < sym_n; ++i) {
|
|
for (unsigned i = 0; i < sym_n; ++i) {
|
|
- output_reloc(outf, buf, &sym[i].st_value);
|
|
|
|
|
|
+ output_reloc(outf, buf, &target_sym[i].st_value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -311,4 +342,9 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap)
|
|
if (symtab_idx) {
|
|
if (symtab_idx) {
|
|
elfN(search_symtab)(shdr, symtab_idx, buf, need_bswap);
|
|
elfN(search_symtab)(shdr, symtab_idx, buf, need_bswap);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ if (need_bswap) {
|
|
|
|
+ elfN(bswap_ps_hdrs)(buf);
|
|
|
|
+ elfN(bswap_ehdr)(buf);
|
|
|
|
+ }
|
|
}
|
|
}
|