aboutsummaryrefslogtreecommitdiffstats
path: root/gpxe/src/util/iccfix.c
diff options
context:
space:
mode:
Diffstat (limited to 'gpxe/src/util/iccfix.c')
-rw-r--r--gpxe/src/util/iccfix.c156
1 files changed, 156 insertions, 0 deletions
diff --git a/gpxe/src/util/iccfix.c b/gpxe/src/util/iccfix.c
new file mode 100644
index 00000000..303ae9ca
--- /dev/null
+++ b/gpxe/src/util/iccfix.c
@@ -0,0 +1,156 @@
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <elf.h>
+#include <gpxe/tables.h>
+
+#define DEBUG 0
+
+#define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
+
+#define dprintf(...) do { \
+ if ( DEBUG ) \
+ fprintf ( stderr, __VA_ARGS__ ); \
+ } while ( 0 )
+
+#ifdef SELF_INCLUDED
+
+/**
+ * Fix up ICC alignments
+ *
+ * @v elf ELF header
+ * @ret rc Return status code
+ *
+ * See comments in tables.h for an explanation of why this monstrosity
+ * is necessary.
+ */
+static int ICCFIX ( void *elf ) {
+ ELF_EHDR *ehdr = elf;
+ ELF_SHDR *shdr = ( elf + ehdr->e_shoff );
+ size_t shentsize = ehdr->e_shentsize;
+ unsigned int shnum = ehdr->e_shnum;
+ ELF_SHDR *strtab = ( ( ( void * ) shdr ) +
+ ( ehdr->e_shstrndx * shentsize ) );
+ char *strings = ( elf + strtab->sh_offset );
+
+ for ( ; shnum-- ; shdr = ( ( ( void * ) shdr ) + shentsize ) ) {
+ char *name = ( strings + shdr->sh_name );
+ unsigned long align = shdr->sh_addralign;
+ unsigned long new_align;
+
+ if ( ( strncmp ( name, ".tbl.", 5 ) == 0 ) &&
+ ( align >= ICC_ALIGN_HACK_FACTOR ) ) {
+ new_align = ( align / ICC_ALIGN_HACK_FACTOR );
+ shdr->sh_addralign = new_align;
+ dprintf ( "Section \"%s\": alignment %d->%d\n",
+ name, align, new_align );
+ }
+ }
+ return 0;
+}
+
+#else /* SELF_INCLUDED */
+
+#define SELF_INCLUDED
+
+/* Include iccfix32() function */
+#define ELF_EHDR Elf32_Ehdr
+#define ELF_SHDR Elf32_Shdr
+#define ICCFIX iccfix32
+#include "iccfix.c"
+#undef ELF_EHDR
+#undef ELF_SHDR
+#undef ICCFIX
+
+/* Include iccfix64() function */
+#define ELF_EHDR Elf64_Ehdr
+#define ELF_SHDR Elf64_Shdr
+#define ICCFIX iccfix64
+#include "iccfix.c"
+#undef ELF_EHDR
+#undef ELF_SHDR
+#undef ICCFIX
+
+static int iccfix ( const char *filename ) {
+ int fd;
+ struct stat stat;
+ void *elf;
+ unsigned char *eident;
+ int rc;
+
+ /* Open and mmap file */
+ fd = open ( filename, O_RDWR );
+ if ( fd < 0 ) {
+ eprintf ( "Could not open %s: %s\n",
+ filename, strerror ( errno ) );
+ rc = -1;
+ goto err_open;
+ }
+ if ( fstat ( fd, &stat ) < 0 ) {
+ eprintf ( "Could not determine size of %s: %s\n",
+ filename, strerror ( errno ) );
+ rc = -1;
+ goto err_fstat;
+ }
+ elf = mmap ( NULL, stat.st_size, ( PROT_READ | PROT_WRITE ),
+ MAP_SHARED, fd, 0 );
+ if ( elf == MAP_FAILED ) {
+ eprintf ( "Could not map %s: %s\n",
+ filename, strerror ( errno ) );
+ rc = -1;
+ goto err_mmap;
+ }
+
+ /* Perform fixups */
+ eident = elf;
+ switch ( eident[EI_CLASS] ) {
+ case ELFCLASS32:
+ rc = iccfix32 ( elf );
+ break;
+ case ELFCLASS64:
+ rc = iccfix64 ( elf );
+ break;
+ default:
+ eprintf ( "Unknown ELF class %d in %s\n",
+ eident[EI_CLASS], filename );
+ rc = -1;
+ break;
+ }
+
+ munmap ( elf, stat.st_size );
+ err_mmap:
+ err_fstat:
+ close ( fd );
+ err_open:
+ return rc;
+}
+
+int main ( int argc, char **argv ) {
+ int i;
+ int rc;
+
+ /* Parse command line */
+ if ( argc < 2 ) {
+ eprintf ( "Syntax: %s <object_file>...\n", argv[0] );
+ exit ( 1 );
+ }
+
+ /* Process each object in turn */
+ for ( i = 1 ; i < argc ; i++ ) {
+ if ( ( rc = iccfix ( argv[i] ) ) != 0 ) {
+ eprintf ( "Could not fix up %s\n", argv[i] );
+ exit ( 1 );
+ }
+ }
+
+ return 0;
+}
+
+#endif /* SELF_INCLUDED */