mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-22 12:54:37 +00:00
tools: relocate-rela: Fix ELF decoding on big-endian hosts
The new ELF decoding logic assumed that the target binary has the same endianness as the host, which broke building ARM64 firmware binaries on big-endian machines. This commit fixes the ELF64 decoding to be host-endianness-neutral, and applies the same changes to the ELF32 decoding. It does not fix the microblaze-specific dynamic symbol decoding. It also corrects the functions used for byte swapping in rela_elf64() and rela_elf32(). The result is the same, but semantically the code is converting bytes read from a foreign-endianness file to host byte order. Fixes:4c9e2d6434
("tools: relocate-rela: Read rela start/end directly from ELF") Fixes:a1405d9cfe
("tools: relocate-rela: Check that relocation works only for EM_AARCH64") Signed-off-by: Samuel Holland <samuel@sholland.org> Link: https://lore.kernel.org/r/20220715064026.54551-1-samuel@sholland.org Signed-off-by: Michal Simek <michal.simek@amd.com>
This commit is contained in:
parent
71f0773148
commit
5e0e1a86d3
1 changed files with 68 additions and 57 deletions
|
@ -60,7 +60,9 @@ static int decode_elf64(FILE *felf, char **argv)
|
||||||
{
|
{
|
||||||
size_t size;
|
size_t size;
|
||||||
Elf64_Ehdr header;
|
Elf64_Ehdr header;
|
||||||
uint64_t section_header_base, section_header_size, sh_offset, sh_size;
|
uint64_t section_header_base, section_header_size;
|
||||||
|
uint64_t sh_addr, sh_offset, sh_size;
|
||||||
|
Elf64_Half sh_index, sh_num;
|
||||||
Elf64_Shdr *sh_table; /* Elf symbol table */
|
Elf64_Shdr *sh_table; /* Elf symbol table */
|
||||||
int ret, i, machine;
|
int ret, i, machine;
|
||||||
char *sh_str;
|
char *sh_str;
|
||||||
|
@ -76,7 +78,7 @@ static int decode_elf64(FILE *felf, char **argv)
|
||||||
return 25;
|
return 25;
|
||||||
}
|
}
|
||||||
|
|
||||||
machine = header.e_machine;
|
machine = le16_to_cpu(header.e_machine);
|
||||||
debug("Machine\t%d\n", machine);
|
debug("Machine\t%d\n", machine);
|
||||||
|
|
||||||
if (machine != EM_AARCH64) {
|
if (machine != EM_AARCH64) {
|
||||||
|
@ -84,9 +86,10 @@ static int decode_elf64(FILE *felf, char **argv)
|
||||||
return 30;
|
return 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
text_base = header.e_entry;
|
text_base = le64_to_cpu(header.e_entry);
|
||||||
section_header_base = header.e_shoff;
|
section_header_base = le64_to_cpu(header.e_shoff);
|
||||||
section_header_size = header.e_shentsize * header.e_shnum;
|
section_header_size = le16_to_cpu(header.e_shentsize) *
|
||||||
|
le16_to_cpu(header.e_shnum);
|
||||||
|
|
||||||
sh_table = malloc(section_header_size);
|
sh_table = malloc(section_header_size);
|
||||||
if (!sh_table) {
|
if (!sh_table) {
|
||||||
|
@ -114,9 +117,9 @@ static int decode_elf64(FILE *felf, char **argv)
|
||||||
return 27;
|
return 27;
|
||||||
}
|
}
|
||||||
|
|
||||||
sh_size = sh_table[header.e_shstrndx].sh_size;
|
sh_index = le16_to_cpu(header.e_shstrndx);
|
||||||
debug("e_shstrndx\t0x%08x\n", header.e_shstrndx);
|
sh_size = le64_to_cpu(sh_table[sh_index].sh_size);
|
||||||
debug("sh_size\t\t0x%08lx\n", sh_size);
|
debug("e_shstrndx %x, sh_size %lx\n", sh_index, sh_size);
|
||||||
|
|
||||||
sh_str = malloc(sh_size);
|
sh_str = malloc(sh_size);
|
||||||
if (!sh_str) {
|
if (!sh_str) {
|
||||||
|
@ -130,9 +133,8 @@ static int decode_elf64(FILE *felf, char **argv)
|
||||||
* Specifies the byte offset from the beginning of the file
|
* Specifies the byte offset from the beginning of the file
|
||||||
* to the first byte in the section.
|
* to the first byte in the section.
|
||||||
*/
|
*/
|
||||||
sh_offset = sh_table[header.e_shstrndx].sh_offset;
|
sh_offset = le64_to_cpu(sh_table[sh_index].sh_offset);
|
||||||
|
sh_num = le16_to_cpu(header.e_shnum);
|
||||||
debug("sh_offset\t0x%08x\n", header.e_shnum);
|
|
||||||
|
|
||||||
ret = fseek(felf, sh_offset, SEEK_SET);
|
ret = fseek(felf, sh_offset, SEEK_SET);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -153,18 +155,22 @@ static int decode_elf64(FILE *felf, char **argv)
|
||||||
return 30;
|
return 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < header.e_shnum; i++) {
|
for (i = 0; i < sh_num; i++) {
|
||||||
/* fprintf(stderr, "%s\n", sh_str + sh_table[i].sh_name); Debug only */
|
char *sh_name = sh_str + le32_to_cpu(sh_table[i].sh_name);
|
||||||
if (!strcmp(".rela.dyn", (sh_str + sh_table[i].sh_name))) {
|
|
||||||
|
debug("%s\n", sh_name);
|
||||||
|
|
||||||
|
sh_addr = le64_to_cpu(sh_table[i].sh_addr);
|
||||||
|
sh_offset = le64_to_cpu(sh_table[i].sh_offset);
|
||||||
|
sh_size = le64_to_cpu(sh_table[i].sh_size);
|
||||||
|
|
||||||
|
if (!strcmp(".rela.dyn", sh_name)) {
|
||||||
debug("Found section\t\".rela_dyn\"\n");
|
debug("Found section\t\".rela_dyn\"\n");
|
||||||
debug(" at addr\t0x%08x\n",
|
debug(" at addr\t0x%08x\n", sh_addr);
|
||||||
(unsigned int)sh_table[i].sh_addr);
|
debug(" at offset\t0x%08x\n", sh_offset);
|
||||||
debug(" at offset\t0x%08x\n",
|
debug(" of size\t0x%08x\n", sh_size);
|
||||||
(unsigned int)sh_table[i].sh_offset);
|
rela_start = sh_addr;
|
||||||
debug(" of size\t0x%08x\n",
|
rela_end = rela_start + sh_size;
|
||||||
(unsigned int)sh_table[i].sh_size);
|
|
||||||
rela_start = sh_table[i].sh_addr;
|
|
||||||
rela_end = rela_start + sh_table[i].sh_size;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,7 +194,9 @@ static int decode_elf32(FILE *felf, char **argv)
|
||||||
{
|
{
|
||||||
size_t size;
|
size_t size;
|
||||||
Elf32_Ehdr header;
|
Elf32_Ehdr header;
|
||||||
uint64_t section_header_base, section_header_size, sh_offset, sh_size;
|
uint64_t section_header_base, section_header_size;
|
||||||
|
uint32_t sh_addr, sh_offset, sh_size;
|
||||||
|
Elf32_Half sh_index, sh_num;
|
||||||
Elf32_Shdr *sh_table; /* Elf symbol table */
|
Elf32_Shdr *sh_table; /* Elf symbol table */
|
||||||
int ret, i, machine;
|
int ret, i, machine;
|
||||||
char *sh_str;
|
char *sh_str;
|
||||||
|
@ -204,7 +212,7 @@ static int decode_elf32(FILE *felf, char **argv)
|
||||||
return 25;
|
return 25;
|
||||||
}
|
}
|
||||||
|
|
||||||
machine = header.e_machine;
|
machine = le16_to_cpu(header.e_machine);
|
||||||
debug("Machine %d\n", machine);
|
debug("Machine %d\n", machine);
|
||||||
|
|
||||||
if (machine != EM_MICROBLAZE) {
|
if (machine != EM_MICROBLAZE) {
|
||||||
|
@ -212,14 +220,10 @@ static int decode_elf32(FILE *felf, char **argv)
|
||||||
return 30;
|
return 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
text_base = header.e_entry;
|
text_base = le32_to_cpu(header.e_entry);
|
||||||
section_header_base = header.e_shoff;
|
section_header_base = le32_to_cpu(header.e_shoff);
|
||||||
|
section_header_size = le16_to_cpu(header.e_shentsize) *
|
||||||
debug("Section header base %x\n", section_header_base);
|
le16_to_cpu(header.e_shnum);
|
||||||
|
|
||||||
section_header_size = header.e_shentsize * header.e_shnum;
|
|
||||||
|
|
||||||
debug("Section header size %d\n", section_header_size);
|
|
||||||
|
|
||||||
sh_table = malloc(section_header_size);
|
sh_table = malloc(section_header_size);
|
||||||
if (!sh_table) {
|
if (!sh_table) {
|
||||||
|
@ -247,8 +251,9 @@ static int decode_elf32(FILE *felf, char **argv)
|
||||||
return 27;
|
return 27;
|
||||||
}
|
}
|
||||||
|
|
||||||
sh_size = sh_table[header.e_shstrndx].sh_size;
|
sh_index = le16_to_cpu(header.e_shstrndx);
|
||||||
debug("e_shstrndx %x, sh_size %lx\n", header.e_shstrndx, sh_size);
|
sh_size = le32_to_cpu(sh_table[sh_index].sh_size);
|
||||||
|
debug("e_shstrndx %x, sh_size %lx\n", sh_index, sh_size);
|
||||||
|
|
||||||
sh_str = malloc(sh_size);
|
sh_str = malloc(sh_size);
|
||||||
if (!sh_str) {
|
if (!sh_str) {
|
||||||
|
@ -262,9 +267,8 @@ static int decode_elf32(FILE *felf, char **argv)
|
||||||
* Specifies the byte offset from the beginning of the file
|
* Specifies the byte offset from the beginning of the file
|
||||||
* to the first byte in the section.
|
* to the first byte in the section.
|
||||||
*/
|
*/
|
||||||
sh_offset = sh_table[header.e_shstrndx].sh_offset;
|
sh_offset = le32_to_cpu(sh_table[sh_index].sh_offset);
|
||||||
|
sh_num = le16_to_cpu(header.e_shnum);
|
||||||
debug("sh_offset %x\n", header.e_shnum);
|
|
||||||
|
|
||||||
ret = fseek(felf, sh_offset, SEEK_SET);
|
ret = fseek(felf, sh_offset, SEEK_SET);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -277,7 +281,7 @@ static int decode_elf32(FILE *felf, char **argv)
|
||||||
|
|
||||||
size = fread(sh_str, 1, sh_size, felf);
|
size = fread(sh_str, 1, sh_size, felf);
|
||||||
if (size != sh_size) {
|
if (size != sh_size) {
|
||||||
fprintf(stderr, "%s: Can't read section: %lx/%lx\n",
|
fprintf(stderr, "%s: Can't read section: %lx/%x\n",
|
||||||
argv[0], size, sh_size);
|
argv[0], size, sh_size);
|
||||||
free(sh_str);
|
free(sh_str);
|
||||||
free(sh_table);
|
free(sh_table);
|
||||||
|
@ -285,22 +289,29 @@ static int decode_elf32(FILE *felf, char **argv)
|
||||||
return 30;
|
return 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < header.e_shnum; i++) {
|
for (i = 0; i < sh_num; i++) {
|
||||||
debug("%s\n", sh_str + sh_table[i].sh_name);
|
char *sh_name = sh_str + le32_to_cpu(sh_table[i].sh_name);
|
||||||
if (!strcmp(".rela.dyn", (sh_str + sh_table[i].sh_name))) {
|
|
||||||
|
debug("%s\n", sh_name);
|
||||||
|
|
||||||
|
sh_addr = le64_to_cpu(sh_table[i].sh_addr);
|
||||||
|
sh_offset = le64_to_cpu(sh_table[i].sh_offset);
|
||||||
|
sh_size = le64_to_cpu(sh_table[i].sh_size);
|
||||||
|
|
||||||
|
if (!strcmp(".rela.dyn", sh_name)) {
|
||||||
debug("Found section\t\".rela_dyn\"\n");
|
debug("Found section\t\".rela_dyn\"\n");
|
||||||
debug(" at addr\t0x%08x\n", (unsigned int)sh_table[i].sh_addr);
|
debug(" at addr\t0x%08x\n", sh_addr);
|
||||||
debug(" at offset\t0x%08x\n", (unsigned int)sh_table[i].sh_offset);
|
debug(" at offset\t0x%08x\n", sh_offset);
|
||||||
debug(" of size\t0x%08x\n", (unsigned int)sh_table[i].sh_size);
|
debug(" of size\t0x%08x\n", sh_size);
|
||||||
rela_start = sh_table[i].sh_addr;
|
rela_start = sh_addr;
|
||||||
rela_end = rela_start + sh_table[i].sh_size;
|
rela_end = rela_start + sh_size;
|
||||||
}
|
}
|
||||||
if (!strcmp(".dynsym", (sh_str + sh_table[i].sh_name))) {
|
if (!strcmp(".dynsym", sh_name)) {
|
||||||
debug("Found section\t\".dynsym\"\n");
|
debug("Found section\t\".dynsym\"\n");
|
||||||
debug(" at addr\t0x%08x\n", (unsigned int)sh_table[i].sh_addr);
|
debug(" at addr\t0x%08x\n", sh_addr);
|
||||||
debug(" at offset\t0x%08x\n", (unsigned int)sh_table[i].sh_offset);
|
debug(" at offset\t0x%08x\n", sh_offset);
|
||||||
debug(" of size\t0x%08x\n", (unsigned int)sh_table[i].sh_size);
|
debug(" of size\t0x%08x\n", sh_size);
|
||||||
dyn_start = sh_table[i].sh_addr;
|
dyn_start = sh_addr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,9 +397,9 @@ static int rela_elf64(char **argv, FILE *f)
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
swrela.r_offset = cpu_to_le64(rela.r_offset);
|
swrela.r_offset = le64_to_cpu(rela.r_offset);
|
||||||
swrela.r_info = cpu_to_le64(rela.r_info);
|
swrela.r_info = le64_to_cpu(rela.r_info);
|
||||||
swrela.r_addend = cpu_to_le64(rela.r_addend);
|
swrela.r_addend = le64_to_cpu(rela.r_addend);
|
||||||
|
|
||||||
if (!supported_rela(&swrela))
|
if (!supported_rela(&swrela))
|
||||||
continue;
|
continue;
|
||||||
|
@ -487,9 +498,9 @@ static int rela_elf32(char **argv, FILE *f)
|
||||||
PRIu32 " r_addend:\t%" PRIx32 "\n",
|
PRIu32 " r_addend:\t%" PRIx32 "\n",
|
||||||
rela.r_offset, rela.r_info, rela.r_addend);
|
rela.r_offset, rela.r_info, rela.r_addend);
|
||||||
|
|
||||||
swrela.r_offset = cpu_to_le32(rela.r_offset);
|
swrela.r_offset = le32_to_cpu(rela.r_offset);
|
||||||
swrela.r_info = cpu_to_le32(rela.r_info);
|
swrela.r_info = le32_to_cpu(rela.r_info);
|
||||||
swrela.r_addend = cpu_to_le32(rela.r_addend);
|
swrela.r_addend = le32_to_cpu(rela.r_addend);
|
||||||
|
|
||||||
debug("SWRela:\toffset:\t%" PRIx32 " r_info:\t%"
|
debug("SWRela:\toffset:\t%" PRIx32 " r_info:\t%"
|
||||||
PRIu32 " r_addend:\t%" PRIx32 "\n",
|
PRIu32 " r_addend:\t%" PRIx32 "\n",
|
||||||
|
|
Loading…
Add table
Reference in a new issue