From 32575e46acd5d569ee3119b6cab1770e92245b89 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Thu, 6 May 2010 16:14:00 -0700 Subject: [PATCH] ELF support for 8-bit relocations Support 8-bit relocations (OUT_ADDRESS and OUT_REL1ADR) in ELF. Signed-off-by: H. Peter Anvin --- output/outelf32.c | 84 ++++++++++++++++++++++++++++++++++++++----------------- output/outelf64.c | 43 +++++++++++++++++++++------- 2 files changed, 92 insertions(+), 35 deletions(-) diff --git a/output/outelf32.c b/output/outelf32.c index 4d238a72..8a14af45 100644 --- a/output/outelf32.c +++ b/output/outelf32.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * Copyright 1996-2010 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -715,7 +715,8 @@ static void elf_out(int32_t segto, const void *data, { struct Section *s; int32_t addr; - uint8_t mydata[4], *p; + uint8_t mydata[8], *p; + int reltype, bytes; int i; static struct symlininfo sinfo; @@ -761,18 +762,24 @@ static void elf_out(int32_t segto, const void *data, return; } - if (type == OUT_RESERVE) { + switch (type) { + case OUT_RESERVE: if (s->type == SHT_PROGBITS) { nasm_error(ERR_WARNING, "uninitialized space declared in" " non-BSS section `%s': zeroing", s->name); elf_sect_write(s, NULL, size); } else s->len += size; - } else if (type == OUT_RAWDATA) { + break; + + case OUT_RAWDATA: if (segment != NO_SEG) nasm_error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); elf_sect_write(s, data, size); - } else if (type == OUT_ADDRESS) { + break; + + case OUT_ADDRESS: + { bool gnu16 = false; addr = *(int64_t *)data; if (segment != NO_SEG) { @@ -781,11 +788,20 @@ static void elf_out(int32_t segto, const void *data, " segment base references"); } else { if (wrt == NO_SEG) { - if (size == 2) { - gnu16 = true; + switch (size) { + case 1: + gnu16 = true; + elf_add_reloc(s, segment, R_386_8); + break; + case 2: + gnu16 = true; elf_add_reloc(s, segment, R_386_16); - } else { + break; + case 4: elf_add_reloc(s, segment, R_386_32); + break; + default: /* Error issued further down */ + break; } } else if (wrt == elf_gotpc_sect + 1) { /* @@ -825,36 +841,45 @@ static void elf_out(int32_t segto, const void *data, p = mydata; if (gnu16) { nasm_error(ERR_WARNING | ERR_WARN_GNUELF, - "16-bit relocations in ELF is a GNU extension"); - WRITESHORT(p, addr); - } else { - if (size != 4 && segment != NO_SEG) { - nasm_error(ERR_NONFATAL, - "Unsupported non-32-bit ELF relocation"); - } - WRITELONG(p, addr); + "8- or 16-bit relocations in ELF32 is a GNU extension"); + } else if (size != 4 && segment != NO_SEG) { + nasm_error(ERR_NONFATAL, "Unsupported non-32-bit ELF relocation"); } + WRITEADDR(p, addr, size); elf_sect_write(s, mydata, size); - } else if (type == OUT_REL2ADR) { - if (segment == segto) - nasm_error(ERR_PANIC, "intra-segment OUT_REL2ADR"); + break; + } + + case OUT_REL1ADR: + bytes = 1; + reltype = R_386_PC8; + goto rel12adr; + case OUT_REL2ADR: + bytes = 2; + reltype = R_386_PC16; + goto rel12adr; + + rel12adr: + nasm_assert(segment != segto); if (segment != NO_SEG && segment % 2) { nasm_error(ERR_NONFATAL, "ELF format does not support" " segment base references"); } else { if (wrt == NO_SEG) { nasm_error(ERR_WARNING | ERR_WARN_GNUELF, - "16-bit relocations in ELF is a GNU extension"); - elf_add_reloc(s, segment, R_386_PC16); + "8- or 16-bit relocations in ELF is a GNU extension"); + elf_add_reloc(s, segment, reltype); } else { nasm_error(ERR_NONFATAL, "Unsupported non-32-bit ELF relocation"); } } - p = mydata; + p = mydata; WRITESHORT(p, *(int64_t *)data - size); - elf_sect_write(s, mydata, 2L); - } else if (type == OUT_REL4ADR) { + elf_sect_write(s, mydata, bytes); + break; + + case OUT_REL4ADR: if (segment == segto) nasm_error(ERR_PANIC, "intra-segment OUT_REL4ADR"); if (segment != NO_SEG && segment % 2) { @@ -876,9 +901,18 @@ static void elf_out(int32_t segto, const void *data, wrt = NO_SEG; /* we can at least _try_ to continue */ } } - p = mydata; + p = mydata; WRITELONG(p, *(int64_t *)data - size); elf_sect_write(s, mydata, 4L); + break; + + case OUT_REL8ADR: + nasm_error(ERR_NONFATAL, + "32-bit ELF format does not support 64-bit relocations"); + p = mydata; + WRITEDLONG(p, 0); + elf_sect_write(s, mydata, 8L); + break; } } diff --git a/output/outelf64.c b/output/outelf64.c index 47581b4b..76a64648 100644 --- a/output/outelf64.c +++ b/output/outelf64.c @@ -724,6 +724,7 @@ static void elf_out(int32_t segto, const void *data, { struct Section *s; int64_t addr, zero; + int reltype, bytes; int i; static struct symlininfo sinfo; @@ -783,18 +784,23 @@ static void elf_out(int32_t segto, const void *data, return; } - if (type == OUT_RESERVE) { + switch (type) { + case OUT_RESERVE: if (s->type == SHT_PROGBITS) { nasm_error(ERR_WARNING, "uninitialized space declared in" " non-BSS section `%s': zeroing", s->name); elf_sect_write(s, NULL, size); } else s->len += size; - } else if (type == OUT_RAWDATA) { + break; + + case OUT_RAWDATA: if (segment != NO_SEG) nasm_error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); elf_sect_write(s, data, size); - } else if (type == OUT_ADDRESS) { + break; + + case OUT_ADDRESS: addr = *(int64_t *)data; if (segment == NO_SEG) { /* Do nothing */ @@ -889,10 +895,22 @@ static void elf_out(int32_t segto, const void *data, } } elf_sect_writeaddr(s, addr, size); - } else if (type == OUT_REL2ADR) { + break; + + case OUT_REL1ADR: + reltype = R_X86_64_PC8; + bytes = 1; + goto rel12adr; + + case OUT_REL2ADR: + reltype = R_X86_64_PC16; + bytes = 2; + goto rel12adr; + + rel12adr: addr = *(int64_t *)data - size; if (segment == segto) - nasm_error(ERR_PANIC, "intra-segment OUT_REL2ADR"); + nasm_error(ERR_PANIC, "intra-segment OUT_REL1ADR"); if (segment == NO_SEG) { /* Do nothing */ } else if (segment % 2) { @@ -900,15 +918,17 @@ static void elf_out(int32_t segto, const void *data, " segment base references"); } else { if (wrt == NO_SEG) { - elf_add_reloc(s, segment, addr, R_X86_64_PC16); + elf_add_reloc(s, segment, addr, reltype); addr = 0; } else { nasm_error(ERR_NONFATAL, - "Unsupported non-32-bit ELF relocation [2]"); + "Unsupported non-32-bit ELF relocation"); } } - elf_sect_writeaddr(s, addr, 2); - } else if (type == OUT_REL4ADR) { + elf_sect_writeaddr(s, addr, bytes); + break; + + case OUT_REL4ADR: addr = *(int64_t *)data - size; if (segment == segto) nasm_error(ERR_PANIC, "intra-segment OUT_REL4ADR"); @@ -944,7 +964,9 @@ static void elf_out(int32_t segto, const void *data, } } elf_sect_writeaddr(s, addr, 4); - } else if (type == OUT_REL8ADR) { + break; + + case OUT_REL8ADR: addr = *(int64_t *)data - size; if (segment == segto) nasm_error(ERR_PANIC, "intra-segment OUT_REL8ADR"); @@ -975,6 +997,7 @@ static void elf_out(int32_t segto, const void *data, } } elf_sect_writeaddr(s, addr, 8); + break; } } -- 2.11.4.GIT