Patch to handle different endian in ELF format
"WALT STEVERSON" <[email protected]>
| Newsgroups | gmane.comp.compilers.distcc |
|---|---|
| Message-ID | <[email protected]> |
I'm using distcc in a cross-compiler environment where the target output is an ELF file in big-endian format and the host is little-endian. The debug information in the ELF file was not being rewritten because fix_debug_info.c couldn't handle the case where the target and host endian-isms did not match. I've basically just implemented the TODO about this that was already in the file. Custom byteswap functions were written for portability reasons and I didn't want to add something else to test for in configure. The patch was diff'd from r711 of the trunk. __ distcc mailing list http://distcc.samba.org/ To unsubscribe or change options: https://lists.samba.org/mailman/listinfo/distcc
fix_debug_info_endian_todo.patch
(application/octet-stream, 9.6 KB)
--- distcc-trunk.orig/src/fix_debug_info.c 2010-02-04 09:17:51.000000000 -0600
+++ distcc-trunk.new/src/fix_debug_info.c 2010-02-04 09:30:52.000000000 -0600
@@ -53,6 +53,42 @@
#endif
#ifdef HAVE_ELF_H
+
+static uint16_t elf_bswap_16(uint16_t halfword)
+{
+ return (halfword >> 8) | (halfword << 8);
+}
+
+static uint32_t elf_bswap_32(uint32_t word)
+{
+ return ((uint32_t)elf_bswap_16(word & 0xffff) << 16) | (elf_bswap_16(word >> 16));
+}
+
+static uint64_t elf_bswap_64(uint64_t xword)
+{
+ return ((uint64_t)elf_bswap_32(xword & 0xffffffffULL) << 32) | (elf_bswap_32(xword >> 32));
+}
+
+
+
+#define GET_ELF32_HALF(loc, byteswap) (Elf32_Half) ((byteswap) ? elf_bswap_16(loc) : loc)
+#define GET_ELF32_WORD(loc, byteswap) (Elf32_Word) ((byteswap) ? elf_bswap_32(loc) : loc)
+#define GET_ELF32_SWORD(loc, byteswap) (Elf32_Sword) ((byteswap) ? elf_bswap_32(loc) : loc)
+#define GET_ELF32_XWORD(loc, byteswap) (Elf32_Xword) ((byteswap) ? elf_bswap_64(loc) : loc)
+#define GET_ELF32_SXWORD(loc, byteswap) (Elf32_Sxword) ((byteswap) ? elf_bswap_64(loc) : loc)
+#define GET_ELF32_ADDR(loc, byteswap) (Elf32_Addr) ((byteswap) ? elf_bswap_32(loc) : loc)
+#define GET_ELF32_OFFSET(loc, byteswap) (Elf32_Off) ((byteswap) ? elf_bswap_32(loc) : loc)
+#define GET_ELF32_VERSYM(loc, byteswap) (Elf32_Versym) ((byteswap) ? elf_bswap_16(loc) : loc)
+
+#define GET_ELF64_HALF(loc, byteswap) (Elf64_Half) ((byteswap) ? elf_bswap_16(loc) : loc)
+#define GET_ELF64_WORD(loc, byteswap) (Elf64_Word) ((byteswap) ? elf_bswap_32(loc) : loc)
+#define GET_ELF64_SWORD(loc, byteswap) (Elf64_Sword) ((byteswap) ? elf_bswap_32(loc) : loc)
+#define GET_ELF64_XWORD(loc, byteswap) (Elf64_Xword) ((byteswap) ? elf_bswap_64(loc) : loc)
+#define GET_ELF64_SXWORD(loc, byteswap) (Elf64_Sxword) ((byteswap) ? elf_bswap_64(loc) : loc)
+#define GET_ELF64_ADDR(loc, byteswap) (Elf64_Addr) ((byteswap) ? elf_bswap_64(loc) : loc)
+#define GET_ELF64_OFFSET(loc, byteswap) (Elf64_Off) ((byteswap) ? elf_bswap_64(loc) : loc)
+#define GET_ELF64_VERSYM(loc, byteswap) (Elf64_Versym) ((byteswap) ? elf_bswap_16(loc) : loc)
+
/*
* Search for an ELF section of the specified name and type.
* Given an ELF file that has been mmapped (or read) into memory starting
@@ -68,6 +104,7 @@
const Elf32_Ehdr *elf32_header = (const Elf32_Ehdr *) (const void *) elf_base;
unsigned int i;
unsigned int num_sections;
+ unsigned int byteswap = 0;
assert(elf_mapped_base);
assert(section_start);
@@ -102,22 +139,17 @@
* enddianness, because ELF header fields use the same endianness
* as the target computer. When cross-compiling to a target with
* a different endianness, we would need to byte-swap all the fields
- * that we use. Right now we don't handle that case.
- *
- * TODO(fergus):
- * handle object files with different endianness than the host.
+ * that we use.
*/
#if WORDS_BIGENDIAN
if (elf32_header->e_ident[EI_DATA] != ELFDATA2MSB) {
- rs_trace("sorry, not fixing debug info: "
- "distcc server host is big-endian, object file is not");
- return 0;
+ rs_trace("distcc server host is big-endian, object file is not");
+ byteswap = 1;
}
#else
if (elf32_header->e_ident[EI_DATA] != ELFDATA2LSB) {
- rs_trace("sorry, not fixing debug info: "
- "distcc server host is little-endian, object file is not");
- return 0;
+ rs_trace("distcc server host is little-endian, object file is not");
+ byteswap = 1;
}
#endif
@@ -130,45 +162,45 @@
const Elf32_Ehdr *elf_header = elf32_header;
const Elf32_Shdr *sections =
/* The double cast below avoids warnings with -Wcast-align. */
- (const Elf32_Shdr *) (const void *) (elf_base + elf_header->e_shoff);
- const Elf32_Shdr *string_section = sections + elf_header->e_shstrndx;
+ (const Elf32_Shdr *) (const void *) (elf_base + GET_ELF32_OFFSET(elf_header->e_shoff, byteswap));
+ const Elf32_Shdr *string_section = sections + GET_ELF32_HALF(elf_header->e_shstrndx, byteswap);
const Elf32_Shdr *desired_section = NULL;
if (elf_size < (off_t) sizeof(*elf_header)) {
rs_trace("object file is too small for ELF header; maybe got truncated?");
return 0;
}
- if (elf_header->e_shoff <= 0 ||
- elf_header->e_shoff > elf_size - sizeof(Elf32_Shdr)) {
+ if (GET_ELF32_OFFSET(elf_header->e_shoff, byteswap) <= 0 ||
+ GET_ELF32_OFFSET(elf_header->e_shoff, byteswap) > elf_size - sizeof(Elf32_Shdr)) {
rs_trace("invalid e_shoff value in ELF header");
return 0;
}
- if (elf_header->e_shstrndx == SHN_UNDEF) {
+ if (GET_ELF32_HALF(elf_header->e_shstrndx, byteswap) == SHN_UNDEF) {
rs_trace("object file has no section name string table"
" (e_shstrndx == SHN_UNDEF)");
return 0;
}
/* Special case for more sections than will fit in e_shstrndx. */
- if (elf_header->e_shstrndx == SHN_XINDEX) {
- string_section = sections + sections[0].sh_link;
+ if (GET_ELF32_HALF(elf_header->e_shstrndx, byteswap) == SHN_XINDEX) {
+ string_section = sections + GET_ELF32_WORD(sections[0].sh_link, byteswap);
}
- num_sections = elf_header->e_shnum;
+ num_sections = GET_ELF32_HALF(elf_header->e_shnum, byteswap);
/* Special case for more sections than will fit in e_shnum. */
if (num_sections == 0) {
- num_sections = sections[0].sh_size;
+ num_sections = GET_ELF32_WORD(sections[0].sh_size, byteswap);
}
for (i = 0; i < num_sections; ++i) {
const char *section_name = (char *)(elf_base +
- string_section->sh_offset +
- sections[i].sh_name);
+ GET_ELF32_OFFSET(string_section->sh_offset, byteswap) +
+ GET_ELF32_WORD(sections[i].sh_name, byteswap));
if (!strcmp(section_name, desired_section_name)) {
desired_section = §ions[i];
break;
}
}
- if (desired_section != NULL && desired_section->sh_size > 0) {
- int desired_section_size = desired_section->sh_size;
- *section_start = elf_base + desired_section->sh_offset;
+ if (desired_section != NULL && GET_ELF32_WORD(desired_section->sh_size, byteswap) > 0) {
+ int desired_section_size = GET_ELF32_WORD(desired_section->sh_size, byteswap);
+ *section_start = elf_base + GET_ELF32_OFFSET(desired_section->sh_offset, byteswap);
*section_size = desired_section_size;
return 1;
} else {
@@ -178,45 +210,45 @@
/* The double cast below avoids warnings with -Wcast-align. */
const Elf64_Ehdr *elf_header = (const Elf64_Ehdr *) (const void *) elf_base;
const Elf64_Shdr *sections =
- (const Elf64_Shdr *) (const void *) (elf_base + elf_header->e_shoff);
- const Elf64_Shdr *string_section = sections + elf_header->e_shstrndx;
+ (const Elf64_Shdr *) (const void *) (elf_base + GET_ELF64_OFFSET(elf_header->e_shoff, byteswap));
+ const Elf64_Shdr *string_section = sections + GET_ELF64_HALF(elf_header->e_shstrndx, byteswap);
const Elf64_Shdr *desired_section = NULL;
if (elf_size < (off_t) sizeof(*elf_header)) {
rs_trace("object file is too small for ELF header; maybe got truncated?");
return 0;
}
- if (elf_header->e_shoff <= 0 ||
- elf_header->e_shoff > (size_t) elf_size - sizeof(Elf64_Shdr)) {
+ if (GET_ELF64_OFFSET(elf_header->e_shoff, byteswap) <= 0 ||
+ GET_ELF64_OFFSET(elf_header->e_shoff, byteswap) > (size_t) elf_size - sizeof(Elf64_Shdr)) {
rs_trace("invalid e_shoff value in ELF header");
return 0;
}
- if (elf_header->e_shstrndx == SHN_UNDEF) {
+ if (GET_ELF64_HALF(elf_header->e_shstrndx, byteswap) == SHN_UNDEF) {
rs_trace("object file has no section name string table"
" (e_shstrndx == SHN_UNDEF)");
return 0;
}
/* Special case for more sections than will fit in e_shstrndx. */
- if (elf_header->e_shstrndx == SHN_XINDEX) {
- string_section = sections + sections[0].sh_link;
+ if (GET_ELF64_HALF(elf_header->e_shstrndx, byteswap) == SHN_XINDEX) {
+ string_section = sections + GET_ELF64_WORD(sections[0].sh_link, byteswap);
}
- num_sections = elf_header->e_shnum;
+ num_sections = GET_ELF64_HALF(elf_header->e_shnum, byteswap);
if (num_sections == 0) {
/* Special case for more sections than will fit in e_shnum. */
- num_sections = sections[0].sh_size;
+ num_sections = GET_ELF64_XWORD(sections[0].sh_size, byteswap);
}
for (i = 0; i < num_sections; ++i) {
const char *section_name = (char*)(elf_base +
- string_section->sh_offset +
- sections[i].sh_name);
+ GET_ELF64_OFFSET(string_section->sh_offset, byteswap) +
+ GET_ELF64_WORD(sections[i].sh_name, byteswap));
if (!strcmp(section_name, desired_section_name)) {
desired_section = §ions[i];
break;
}
}
- if (desired_section != NULL && desired_section->sh_size > 0) {
- int desired_section_size = desired_section->sh_size;
- *section_start = elf_base + desired_section->sh_offset;
+ if (desired_section != NULL && GET_ELF64_XWORD(desired_section->sh_size, byteswap) > 0) {
+ int desired_section_size = GET_ELF64_XWORD(desired_section->sh_size, byteswap);
+ *section_start = elf_base + GET_ELF64_OFFSET(desired_section->sh_offset, byteswap);
*section_size = desired_section_size;
return 1;
} else {