Skip to content
This repository has been archived by the owner on Dec 14, 2022. It is now read-only.

Commit

Permalink
scripts/sortextable: Handle relative entries, and other cleanups
Browse files Browse the repository at this point in the history
x86 is now using relative rather than absolute addresses in its
exception table, so we add a sorter for these.  If there are
relocations on the __ex_table section, they are redundant and probably
incorrect after the sort, so they are zeroed out leaving them valid
and consistent.

Also use the unaligned safe accessors from tools/{be,le}_byteshift.h

Signed-off-by: David Daney <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: H. Peter Anvin <[email protected]>
  • Loading branch information
daviddaney authored and H. Peter Anvin committed Apr 24, 2012
1 parent 7062765 commit d59a168
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 88 deletions.
2 changes: 2 additions & 0 deletions scripts/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ hostprogs-$(CONFIG_IKCONFIG) += bin2c
hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable

HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include

always := $(hostprogs-y) $(hostprogs-m)

# The following hostprogs-y programs are only build on demand
Expand Down
171 changes: 111 additions & 60 deletions scripts/sortextable.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* sortextable.c: Sort the kernel's exception table
*
* Copyright 2011 Cavium, Inc.
* Copyright 2011 - 2012 Cavium, Inc.
*
* Based on code taken from recortmcount.c which is:
*
Expand All @@ -28,6 +28,9 @@
#include <string.h>
#include <unistd.h>

#include <tools/be_byteshift.h>
#include <tools/le_byteshift.h>

static int fd_map; /* File descriptor for file being modified. */
static int mmap_failed; /* Boolean flag. */
static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */
Expand Down Expand Up @@ -94,109 +97,157 @@ static void *mmap_file(char const *fname)
return addr;
}

/* w8rev, w8nat, ...: Handle endianness. */

static uint64_t w8rev(uint64_t const x)
static uint64_t r8be(const uint64_t *x)
{
return ((0xff & (x >> (0 * 8))) << (7 * 8))
| ((0xff & (x >> (1 * 8))) << (6 * 8))
| ((0xff & (x >> (2 * 8))) << (5 * 8))
| ((0xff & (x >> (3 * 8))) << (4 * 8))
| ((0xff & (x >> (4 * 8))) << (3 * 8))
| ((0xff & (x >> (5 * 8))) << (2 * 8))
| ((0xff & (x >> (6 * 8))) << (1 * 8))
| ((0xff & (x >> (7 * 8))) << (0 * 8));
return get_unaligned_be64(x);
}

static uint32_t w4rev(uint32_t const x)
static uint32_t rbe(const uint32_t *x)
{
return ((0xff & (x >> (0 * 8))) << (3 * 8))
| ((0xff & (x >> (1 * 8))) << (2 * 8))
| ((0xff & (x >> (2 * 8))) << (1 * 8))
| ((0xff & (x >> (3 * 8))) << (0 * 8));
return get_unaligned_be32(x);
}

static uint32_t w2rev(uint16_t const x)
static uint16_t r2be(const uint16_t *x)
{
return ((0xff & (x >> (0 * 8))) << (1 * 8))
| ((0xff & (x >> (1 * 8))) << (0 * 8));
return get_unaligned_be16(x);
}

static uint64_t w8nat(uint64_t const x)
static uint64_t r8le(const uint64_t *x)
{
return x;
return get_unaligned_le64(x);
}

static uint32_t w4nat(uint32_t const x)
static uint32_t rle(const uint32_t *x)
{
return get_unaligned_le32(x);
}
static uint16_t r2le(const uint16_t *x)
{
return x;
return get_unaligned_le16(x);
}

static uint32_t w2nat(uint16_t const x)
static void w8be(uint64_t val, uint64_t *x)
{
put_unaligned_be64(val, x);
}
static void wbe(uint32_t val, uint32_t *x)
{
put_unaligned_be32(val, x);
}
static void w2be(uint16_t val, uint16_t *x)
{
put_unaligned_be16(val, x);
}
static void w8le(uint64_t val, uint64_t *x)
{
put_unaligned_le64(val, x);
}
static void wle(uint32_t val, uint32_t *x)
{
put_unaligned_le32(val, x);
}
static void w2le(uint16_t val, uint16_t *x)
{
return x;
put_unaligned_le16(val, x);
}

static uint64_t (*w8)(uint64_t);
static uint32_t (*w)(uint32_t);
static uint32_t (*w2)(uint16_t);
static uint64_t (*r8)(const uint64_t *);
static uint32_t (*r)(const uint32_t *);
static uint16_t (*r2)(const uint16_t *);
static void (*w8)(uint64_t, uint64_t *);
static void (*w)(uint32_t, uint32_t *);
static void (*w2)(uint16_t, uint16_t *);

typedef void (*table_sort_t)(char *, int);

/* 32 bit and 64 bit are very similar */
#include "sortextable.h"
#define SORTEXTABLE_64
#include "sortextable.h"

static int compare_x86_table(const void *a, const void *b)
{
int32_t av = (int32_t)r(a);
int32_t bv = (int32_t)r(b);

if (av < bv)
return -1;
if (av > bv)
return 1;
return 0;
}

static void sort_x86_table(char *extab_image, int image_size)
{
int i;

/*
* Do the same thing the runtime sort does, first normalize to
* being relative to the start of the section.
*/
i = 0;
while (i < image_size) {
uint32_t *loc = (uint32_t *)(extab_image + i);
w(r(loc) + i, loc);
i += 4;
}

qsort(extab_image, image_size / 8, 8, compare_x86_table);

/* Now denormalize. */
i = 0;
while (i < image_size) {
uint32_t *loc = (uint32_t *)(extab_image + i);
w(r(loc) - i, loc);
i += 4;
}
}

static void
do_file(char const *const fname)
{
Elf32_Ehdr *const ehdr = mmap_file(fname);
table_sort_t custom_sort;
Elf32_Ehdr *ehdr = mmap_file(fname);

ehdr_curr = ehdr;
w = w4nat;
w2 = w2nat;
w8 = w8nat;
switch (ehdr->e_ident[EI_DATA]) {
static unsigned int const endian = 1;
default:
fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
ehdr->e_ident[EI_DATA], fname);
fail_file();
break;
case ELFDATA2LSB:
if (*(unsigned char const *)&endian != 1) {
/* main() is big endian, file.o is little endian. */
w = w4rev;
w2 = w2rev;
w8 = w8rev;
}
r = rle;
r2 = r2le;
r8 = r8le;
w = wle;
w2 = w2le;
w8 = w8le;
break;
case ELFDATA2MSB:
if (*(unsigned char const *)&endian != 0) {
/* main() is little endian, file.o is big endian. */
w = w4rev;
w2 = w2rev;
w8 = w8rev;
}
r = rbe;
r2 = r2be;
r8 = r8be;
w = wbe;
w2 = w2be;
w8 = w8be;
break;
} /* end switch */
if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0
|| w2(ehdr->e_type) != ET_EXEC
|| r2(&ehdr->e_type) != ET_EXEC
|| ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname);
fail_file();
}

switch (w2(ehdr->e_machine)) {
custom_sort = NULL;
switch (r2(&ehdr->e_machine)) {
default:
fprintf(stderr, "unrecognized e_machine %d %s\n",
w2(ehdr->e_machine), fname);
r2(&ehdr->e_machine), fname);
fail_file();
break;
case EM_386:
case EM_MIPS:
case EM_X86_64:
custom_sort = sort_x86_table;
break;
case EM_MIPS:
break;
} /* end switch */

Expand All @@ -207,23 +258,23 @@ do_file(char const *const fname)
fail_file();
break;
case ELFCLASS32:
if (w2(ehdr->e_ehsize) != sizeof(Elf32_Ehdr)
|| w2(ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr)
|| r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
fprintf(stderr,
"unrecognized ET_EXEC file: %s\n", fname);
fail_file();
}
do32(ehdr, fname);
do32(ehdr, fname, custom_sort);
break;
case ELFCLASS64: {
Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
if (w2(ghdr->e_ehsize) != sizeof(Elf64_Ehdr)
|| w2(ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr)
|| r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
fprintf(stderr,
"unrecognized ET_EXEC file: %s\n", fname);
fail_file();
}
do64(ghdr, fname);
do64(ghdr, fname, custom_sort);
break;
}
} /* end switch */
Expand Down
Loading

0 comments on commit d59a168

Please sign in to comment.