From fd52c277dd6d768545cee39b154e706904581966 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 26 Nov 2013 18:09:56 -0800 Subject: [PATCH] output: Allow OUT_ADDRESS with a negative size to mean signed relocation This only matters for ELF64/ELFx32, at least for now. Signed-off-by: H. Peter Anvin --- output/outaout.c | 18 ++++++++---------- output/outas86.c | 9 +++++---- output/outbin.c | 10 +++++++--- output/outcoff.c | 15 ++++++++------- output/outdbg.c | 11 +++++++---- output/outelf32.c | 49 +++++++++++++++++++++++++++++-------------------- output/outelf64.c | 31 +++++++++++++++++++++++++------ output/outelfx32.c | 29 ++++++++++++++++++++++++----- output/outieee.c | 6 ++++-- output/outmac32.c | 34 +++++++++++++++++++--------------- output/outmac64.c | 14 +++++++++----- output/outobj.c | 5 ++++- output/outrdf2.c | 9 +++++---- 13 files changed, 154 insertions(+), 86 deletions(-) diff --git a/output/outaout.c b/output/outaout.c index e0963924..b9f21ec6 100644 --- a/output/outaout.c +++ b/output/outaout.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * Copyright 1996-2013 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -635,6 +635,7 @@ static void aout_out(int32_t segto, const void *data, nasm_error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); aout_sect_write(s, data, size); } else if (type == OUT_ADDRESS) { + int asize = abs(size); addr = *(int64_t *)data; if (segment != NO_SEG) { if (segment % 2) { @@ -642,8 +643,7 @@ static void aout_out(int32_t segto, const void *data, " segment base references"); } else { if (wrt == NO_SEG) { - aout_add_reloc(s, segment, RELTYPE_ABSOLUTE, - size); + aout_add_reloc(s, segment, RELTYPE_ABSOLUTE, asize); } else if (!bsd) { nasm_error(ERR_NONFATAL, "Linux a.out format does not support" @@ -651,19 +651,17 @@ static void aout_out(int32_t segto, const void *data, wrt = NO_SEG; /* we can at least _try_ to continue */ } else if (wrt == aout_gotpc_sect + 1) { is_pic = 0x40; - aout_add_reloc(s, segment, RELTYPE_GOTPC, size); + aout_add_reloc(s, segment, RELTYPE_GOTPC, asize); } else if (wrt == aout_gotoff_sect + 1) { is_pic = 0x40; - addr = aout_add_gotoff_reloc(s, segment, - addr, size); + addr = aout_add_gotoff_reloc(s, segment, addr, asize); } else if (wrt == aout_got_sect + 1) { is_pic = 0x40; - addr = - aout_add_gsym_reloc(s, segment, addr, RELTYPE_GOT, - size, true); + addr = aout_add_gsym_reloc(s, segment, addr, RELTYPE_GOT, + asize, true); } else if (wrt == aout_sym_sect + 1) { addr = aout_add_gsym_reloc(s, segment, addr, - RELTYPE_ABSOLUTE, size, + RELTYPE_ABSOLUTE, asize, false); } else if (wrt == aout_plt_sect + 1) { is_pic = 0x40; diff --git a/output/outas86.c b/output/outas86.c index b288637b..7af8d785 100644 --- a/output/outas86.c +++ b/output/outas86.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * Copyright 1996-2013 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -345,19 +345,20 @@ static void as86_out(int32_t segto, const void *data, as86_sect_write(s, data, size); as86_add_piece(s, 0, 0L, 0L, size, 0); } else if (type == OUT_ADDRESS) { + int asize = abs(size); if (segment != NO_SEG) { if (segment % 2) { nasm_error(ERR_NONFATAL, "as86 format does not support" " segment base references"); } else { offset = *(int64_t *)data; - as86_add_piece(s, 1, offset, segment, size, 0); + as86_add_piece(s, 1, offset, segment, asize, 0); } } else { p = mydata; WRITELONG(p, *(int64_t *)data); - as86_sect_write(s, data, size); - as86_add_piece(s, 0, 0L, 0L, size, 0); + as86_sect_write(s, data, asize); + as86_add_piece(s, 0, 0L, 0L, asize, 0); } } else if (type == OUT_REL2ADR) { if (segment == segto) diff --git a/output/outbin.c b/output/outbin.c index 21c042db..6dc4b2a6 100644 --- a/output/outbin.c +++ b/output/outbin.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * Copyright 1996-2013 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -762,6 +762,9 @@ static void bin_out(int32_t segto, const void *data, switch (type) { case OUT_ADDRESS: + { + int asize = abs(size); + if (segment != NO_SEG && !find_section_by_index(segment)) { if (segment % 2) nasm_error(ERR_NONFATAL, "binary output format does not support" @@ -775,10 +778,11 @@ static void bin_out(int32_t segto, const void *data, if (segment != NO_SEG) add_reloc(s, size, segment, -1L); p = mydata; - WRITEADDR(p, *(int64_t *)data, size); - saa_wbytes(s->contents, mydata, size); + WRITEADDR(p, *(int64_t *)data, asize); + saa_wbytes(s->contents, mydata, asize); } break; + } case OUT_RAWDATA: if (s->flags & TYPE_PROGBITS) diff --git a/output/outcoff.c b/output/outcoff.c index d0fcb775..3949028b 100644 --- a/output/outcoff.c +++ b/output/outcoff.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2010 The NASM Authors - All Rights Reserved + * Copyright 1996-2013 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -646,8 +646,9 @@ static void coff_out(int32_t segto, const void *data, nasm_error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); coff_sect_write(s, data, size); } else if (type == OUT_ADDRESS) { - if (!(win64)) { - if (size != 4 && (segment != NO_SEG || wrt != NO_SEG)) { + int asize = abs(size); + if (!win64) { + if (asize != 4 && (segment != NO_SEG || wrt != NO_SEG)) { nasm_error(ERR_NONFATAL, "COFF format does not support non-32-bit" " relocations"); } else { @@ -664,25 +665,25 @@ static void coff_out(int32_t segto, const void *data, } p = mydata; WRITELONG(p, *(int64_t *)data + fix); - coff_sect_write(s, mydata, size); + coff_sect_write(s, mydata, asize); } } else { int32_t fix = 0; p = mydata; - if (size == 8) { + if (asize == 8) { if (wrt == imagebase_sect) { nasm_error(ERR_NONFATAL, "operand size mismatch: 'wrt " WRT_IMAGEBASE "' is a 32-bit operand"); } fix = coff_add_reloc(s, segment, IMAGE_REL_AMD64_ADDR64); WRITEDLONG(p, *(int64_t *)data + fix); - coff_sect_write(s, mydata, size); + coff_sect_write(s, mydata, asize); } else { fix = coff_add_reloc(s, segment, wrt == imagebase_sect ? IMAGE_REL_AMD64_ADDR32NB: IMAGE_REL_AMD64_ADDR32); WRITELONG(p, *(int64_t *)data + fix); - coff_sect_write(s, mydata, size); + coff_sect_write(s, mydata, asize); } } } else if (type == OUT_REL2ADR) { diff --git a/output/outdbg.c b/output/outdbg.c index 2b750396..bf145585 100644 --- a/output/outdbg.c +++ b/output/outdbg.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * Copyright 1996-2013 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -127,7 +127,10 @@ static void dbg_out(int32_t segto, const void *data, int32_t ldata; int id; - fprintf(ofile, "out to %"PRIx32", len = %"PRIu64": ", segto, size); + if (type == OUT_ADDRESS) + fprintf(ofile, "out to %"PRIx32", len = %d: ", segto, (int)size); + else + fprintf(ofile, "out to %"PRIx32", len = %"PRIu64": ", segto, size); switch (type) { case OUT_RESERVE: @@ -144,8 +147,8 @@ static void dbg_out(int32_t segto, const void *data, break; case OUT_ADDRESS: ldata = *(int64_t *)data; - fprintf(ofile, "addr %08"PRIx32" (seg %08"PRIx32", wrt %08"PRIx32")\n", ldata, - segment, wrt); + fprintf(ofile, "addr %08"PRIx32" (seg %08"PRIx32", wrt %08"PRIx32")\n", + ldata, segment, wrt); break; case OUT_REL1ADR: fprintf(ofile, "rel1adr %02"PRIx8" (seg %08"PRIx32")\n", diff --git a/output/outelf32.c b/output/outelf32.c index 48f91776..413270bf 100644 --- a/output/outelf32.c +++ b/output/outelf32.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2010 The NASM Authors - All Rights Reserved + * Copyright 1996-2013 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -767,6 +767,7 @@ static void elf_out(int32_t segto, const void *data, case OUT_ADDRESS: { bool gnu16 = false; + int asize = abs(size); addr = *(int64_t *)data; if (segment != NO_SEG) { if (segment % 2) { @@ -779,22 +780,20 @@ static void elf_out(int32_t segto, const void *data, * don't handle switch() statements with 64-bit * expressions. */ - if (size < UINT_MAX) { - switch ((unsigned int)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); - break; - case 4: - elf_add_reloc(s, segment, R_386_32); - break; - default: /* Error issued further down */ - break; - } + switch (asize) { + 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); + 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) { /* @@ -813,13 +812,23 @@ static void elf_out(int32_t segto, const void *data, addr = elf_add_gsym_reloc(s, segment, addr, R_386_GOT32, true); } else if (wrt == elf_sym_sect + 1) { - if (size == 2) { + switch (asize) { + case 1: + gnu16 = true; + addr = elf_add_gsym_reloc(s, segment, addr, + R_386_8, false); + break; + case 2: gnu16 = true; addr = elf_add_gsym_reloc(s, segment, addr, R_386_16, false); - } else { + break; + case 4: addr = elf_add_gsym_reloc(s, segment, addr, R_386_32, false); + break; + default: + break; } } else if (wrt == elf_plt_sect + 1) { nasm_error(ERR_NONFATAL, "ELF format cannot produce non-PC-" @@ -835,7 +844,7 @@ static void elf_out(int32_t segto, const void *data, if (gnu16) { nasm_error(ERR_WARNING | ERR_WARN_GNUELF, "8- or 16-bit relocations in ELF32 is a GNU extension"); - } else if (size != 4 && segment != NO_SEG) { + } else if (asize != 4 && segment != NO_SEG) { nasm_error(ERR_NONFATAL, "Unsupported non-32-bit ELF relocation"); } WRITEADDR(p, addr, size); diff --git a/output/outelf64.c b/output/outelf64.c index 8175aedc..9f93fc82 100644 --- a/output/outelf64.c +++ b/output/outelf64.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2010 The NASM Authors - All Rights Reserved + * Copyright 1996-2013 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -785,6 +785,10 @@ static void elf_out(int32_t segto, const void *data, break; case OUT_ADDRESS: + { + int isize = (int)size; + int asize = abs(size); + addr = *(int64_t *)data; if (segment == NO_SEG) { /* Do nothing */ @@ -793,17 +797,23 @@ static void elf_out(int32_t segto, const void *data, " segment base references"); } else { if (wrt == NO_SEG) { - switch ((int)size) { + switch (isize) { case 1: + case -1: elf_add_reloc(s, segment, addr, R_X86_64_8); break; case 2: + case -2: elf_add_reloc(s, segment, addr, R_X86_64_16); break; case 4: elf_add_reloc(s, segment, addr, R_X86_64_32); break; + case -4: + elf_add_reloc(s, segment, addr, R_X86_64_32S); + break; case 8: + case -8: elf_add_reloc(s, segment, addr, R_X86_64_64); break; default: @@ -821,7 +831,7 @@ static void elf_out(int32_t segto, const void *data, elf_add_reloc(s, segment, addr, R_X86_64_GOTPC32); addr = 0; } else if (wrt == elf_gotoff_sect + 1) { - if (size != 8) { + if (asize != 8) { nasm_error(ERR_NONFATAL, "ELF64 requires ..gotoff " "references to be qword"); } else { @@ -829,7 +839,7 @@ static void elf_out(int32_t segto, const void *data, addr = 0; } } else if (wrt == elf_got_sect + 1) { - switch ((int)size) { + switch (asize) { case 4: elf_add_gsym_reloc(s, segment, addr, 0, R_X86_64_GOT32, true); @@ -845,13 +855,15 @@ static void elf_out(int32_t segto, const void *data, break; } } else if (wrt == elf_sym_sect + 1) { - switch ((int)size) { + switch (isize) { case 1: + case -1: elf_add_gsym_reloc(s, segment, addr, 0, R_X86_64_8, false); addr = 0; break; case 2: + case -2: elf_add_gsym_reloc(s, segment, addr, 0, R_X86_64_16, false); addr = 0; @@ -861,7 +873,13 @@ static void elf_out(int32_t segto, const void *data, R_X86_64_32, false); addr = 0; break; + case -4: + elf_add_gsym_reloc(s, segment, addr, 0, + R_X86_64_32S, false); + addr = 0; + break; case 8: + case -8: elf_add_gsym_reloc(s, segment, addr, 0, R_X86_64_64, false); addr = 0; @@ -878,8 +896,9 @@ static void elf_out(int32_t segto, const void *data, " use of WRT"); } } - elf_sect_writeaddr(s, addr, size); + elf_sect_writeaddr(s, addr, asize); break; + } case OUT_REL1ADR: reltype = R_X86_64_PC8; diff --git a/output/outelfx32.c b/output/outelfx32.c index 57bbf75b..bbedc482 100644 --- a/output/outelfx32.c +++ b/output/outelfx32.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 2012 The NASM Authors - All Rights Reserved + * Copyright 1996-2013 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -783,6 +783,10 @@ static void elf_out(int32_t segto, const void *data, break; case OUT_ADDRESS: + { + int isize = (int)size; + int asize = abs(size); + addr = *(int64_t *)data; if (segment == NO_SEG) { /* Do nothing */ @@ -791,17 +795,23 @@ static void elf_out(int32_t segto, const void *data, " segment base references"); } else { if (wrt == NO_SEG) { - switch ((int)size) { + switch (isize) { case 1: + case -1: elf_add_reloc(s, segment, addr, R_X86_64_8); break; case 2: + case -2: elf_add_reloc(s, segment, addr, R_X86_64_16); break; case 4: elf_add_reloc(s, segment, addr, R_X86_64_32); break; + case -4: + elf_add_reloc(s, segment, addr, R_X86_64_32S); + break; case 8: + case -8: elf_add_reloc(s, segment, addr, R_X86_64_64); break; default: @@ -822,7 +832,7 @@ static void elf_out(int32_t segto, const void *data, nasm_error(ERR_NONFATAL, "ELFX32 doesn't support " "R_X86_64_GOTOFF64"); } else if (wrt == elf_got_sect + 1) { - switch ((int)size) { + switch (asize) { case 4: elf_add_gsym_reloc(s, segment, addr, 0, R_X86_64_GOT32, true); @@ -833,13 +843,15 @@ static void elf_out(int32_t segto, const void *data, break; } } else if (wrt == elf_sym_sect + 1) { - switch ((int)size) { + switch (isize) { case 1: + case -1: elf_add_gsym_reloc(s, segment, addr, 0, R_X86_64_8, false); addr = 0; break; case 2: + case -2: elf_add_gsym_reloc(s, segment, addr, 0, R_X86_64_16, false); addr = 0; @@ -849,7 +861,13 @@ static void elf_out(int32_t segto, const void *data, R_X86_64_32, false); addr = 0; break; + case -4: + elf_add_gsym_reloc(s, segment, addr, 0, + R_X86_64_32S, false); + addr = 0; + break; case 8: + case -8: elf_add_gsym_reloc(s, segment, addr, 0, R_X86_64_64, false); addr = 0; @@ -866,8 +884,9 @@ static void elf_out(int32_t segto, const void *data, " use of WRT"); } } - elf_sect_writeaddr(s, addr, size); + elf_sect_writeaddr(s, addr, asize); break; + } case OUT_REL1ADR: reltype = R_X86_64_PC8; diff --git a/output/outieee.c b/output/outieee.c index 94d5e598..5377ec61 100644 --- a/output/outieee.c +++ b/output/outieee.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * Copyright 1996-2013 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -437,7 +437,9 @@ static void ieee_out(int32_t segto, const void *data, ieee_write_byte(seg, *ucdata++); } else if (type == OUT_ADDRESS || type == OUT_REL2ADR || type == OUT_REL4ADR) { - if (segment == NO_SEG && type != OUT_ADDRESS) + if (type == OUT_ADDRESS) + size = abs(size); + else if (segment == NO_SEG) nasm_error(ERR_NONFATAL, "relative call to absolute address not" " supported by IEEE format"); ldata = *(int64_t *)data; diff --git a/output/outmac32.c b/output/outmac32.c index a13e0d9b..c2c91b48 100644 --- a/output/outmac32.c +++ b/output/outmac32.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * Copyright 1996-2013 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -431,20 +431,24 @@ static void macho_output(int32_t secto, const void *data, break; case OUT_ADDRESS: - addr = *(int64_t *)data; - - if (section != NO_SEG) { - if (section % 2) { - nasm_error(ERR_NONFATAL, "Mach-O format does not support" - " section base references"); - } else - add_reloc(s, section, 0, size); - } - - p = mydata; - WRITEADDR(p, addr, size); - sect_write(s, mydata, size); - break; + { + int asize = abs(size); + + addr = *(int64_t *)data; + + if (section != NO_SEG) { + if (section % 2) { + nasm_error(ERR_NONFATAL, "Mach-O format does not support" + " section base references"); + } else + add_reloc(s, section, 0, asize); + } + + p = mydata; + WRITEADDR(p, addr, asize); + sect_write(s, mydata, asize); + break; + } case OUT_REL2ADR: if (section == secto) diff --git a/output/outmac64.c b/output/outmac64.c index 358ae6e4..abad84aa 100644 --- a/output/outmac64.c +++ b/output/outmac64.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * Copyright 1996-2013 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -528,6 +528,9 @@ static void macho_output(int32_t secto, const void *data, break; case OUT_ADDRESS: + { + int asize = abs(size); + addr = *(int64_t *)data; if (section != NO_SEG) { if (section % 2) { @@ -535,7 +538,7 @@ static void macho_output(int32_t secto, const void *data, " section base references"); } else { if (wrt == NO_SEG) { - if (size < 8) { + if (asize < 8) { nasm_error(ERR_NONFATAL, "Mach-O 64-bit format does not support" " 32-bit absolute addresses"); /* @@ -544,7 +547,7 @@ static void macho_output(int32_t secto, const void *data, making it impractical for use in intermediate object files */ } else { - addr -= add_reloc(s, section, 0, size, addr); // X86_64_RELOC_UNSIGNED + addr -= add_reloc(s, section, 0, asize, addr); // X86_64_RELOC_UNSIGNED } } else { nasm_error(ERR_NONFATAL, "Mach-O format does not support" @@ -554,9 +557,10 @@ static void macho_output(int32_t secto, const void *data, } p = mydata; - WRITEADDR(p, addr, size); - sect_write(s, mydata, size); + WRITEADDR(p, addr, asize); + sect_write(s, mydata, asize); break; + } case OUT_REL2ADR: p = mydata; diff --git a/output/outobj.c b/output/outobj.c index 6fa54190..7fa29b27 100644 --- a/output/outobj.c +++ b/output/outobj.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * Copyright 1996-2013 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -1086,6 +1086,9 @@ static void obj_out(int32_t segto, const void *data, { int rsize; + if (type == OUT_ADDRESS) + size = abs(size); + if (segment == NO_SEG && type != OUT_ADDRESS) nasm_error(ERR_NONFATAL, "relative call to absolute address not" " supported by OBJ format"); diff --git a/output/outrdf2.c b/output/outrdf2.c index 02518a1a..c7aeb28b 100644 --- a/output/outrdf2.c +++ b/output/outrdf2.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2009 The NASM Authors - All Rights Reserved + * Copyright 1996-2013 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -583,6 +583,7 @@ static void rdf2_out(int32_t segto, const void *data, membufwrite(segto, data, size); } else if (type == OUT_ADDRESS) { + int asize = abs(size); /* if segment == NO_SEG then we are writing an address of an object within the same segment - do not produce reloc rec. */ @@ -597,14 +598,14 @@ static void rdf2_out(int32_t segto, const void *data, rr.reclen = 8; rr.segment = segto; /* segment we're currently in */ rr.offset = getsegmentlength(segto); /* current offset */ - rr.length = size; /* length of reference */ + rr.length = asize; /* length of reference */ rr.refseg = segment; /* segment referred to */ write_reloc_rec(&rr); } pd = databuf; /* convert address to little-endian */ - WRITEADDR(pd, *(int64_t *)data, size); - membufwrite(segto, databuf, size); + WRITEADDR(pd, *(int64_t *)data, asize); + membufwrite(segto, databuf, asize); } else if (type == OUT_REL2ADR) { if (segment == segto) nasm_error(ERR_PANIC, "intra-segment OUT_REL2ADR"); -- 2.11.4.GIT