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 = &sections[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 = &sections[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 {
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.