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 <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin 2013-11-26 18:09:56 -08:00
parent 80d18b5555
commit fd52c277dd
13 changed files with 154 additions and 86 deletions

View File

@ -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;

View File

@ -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)

View File

@ -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)

View File

@ -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) {

View File

@ -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",

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -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");

View File

@ -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");