diff options
author | H. Peter Anvin <hpa@linux.intel.com> | 2016-02-21 20:56:19 -0800 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2016-02-21 20:56:19 -0800 |
commit | a222d2113830237bdb7cc7280108528d95530a8c (patch) | |
tree | 73e69069c2d7360cabe48faf00a89f04a5248322 | |
parent | 114ba75f7bb6dbd935b8b72537544d8e8ec49716 (diff) | |
download | nasm-a222d2113830237bdb7cc7280108528d95530a8c.tar.gz |
outmacho: make a best effort at separating SIGNED from BRANCH relocs
For 64 bits, a BRANCH reloc is sometimes needed to fix up PIC
problems. Make a best effort at generating BRANCH relocs just as
we make a best effort at distinguishing GOTLOAD from GOT.
This needs to be replaced with information from the assembler to
the backend.
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r-- | output/outmacho.c | 63 |
1 files changed, 46 insertions, 17 deletions
diff --git a/output/outmacho.c b/output/outmacho.c index 6179cc70..e8c1e999 100644 --- a/output/outmacho.c +++ b/output/outmacho.c @@ -111,6 +111,7 @@ enum reltype { RL_ABS, /* Absolute relocation */ RL_REL, /* Relative relocation */ RL_TLV, /* Thread local */ + RL_BRANCH, /* Relative direct branch */ RL_SUB, /* X86_64_RELOC_SUBTRACT */ RL_GOT, /* X86_64_RELOC_GOT */ RL_GOTLOAD, /* X86_64_RELOC_GOT_LOAD */ @@ -435,8 +436,14 @@ static int64_t add_reloc(struct section *sect, int32_t section, } break; + case RL_BRANCH: + r->type = X86_64_RELOC_BRANCH; + goto rel_or_branch; + case RL_REL: r->type = fmt.reloc_rel; + + rel_or_branch: r->pcrel = 1; if (section == NO_SEG) { goto bail; /* No relocation needed */ @@ -508,8 +515,9 @@ static void macho_output(int32_t secto, const void *data, { struct section *s; int64_t addr, offset; - uint8_t mydata[16], *p, gotload; + uint8_t mydata[16], *p; bool is_bss; + enum reltype reltype; if (secto == NO_SEG) { if (type != OUT_RESERVE) @@ -620,35 +628,56 @@ static void macho_output(int32_t secto, const void *data, p = mydata; offset = *(int64_t *)data; addr = offset - size; + reltype = RL_REL; if (section != NO_SEG && section % 2) { nasm_error(ERR_NONFATAL, "Mach-O format does not support" " section base references"); } else if (wrt == NO_SEG) { - /* Plain relative relocation */ - addr += add_reloc(s, section, offset, RL_REL, 4); - } else if (wrt == macho_gotpcrel_sect) { - if (s->data->datalen > 1) { - /* Retrieve instruction opcode */ - saa_fread(s->data, s->data->datalen-2, &gotload, 1); - } else { - gotload = 0; + if (fmt.ptrsize == 8 && + (s->flags & S_ATTR_SOME_INSTRUCTIONS)) { + uint8_t opcode[2]; + + opcode[0] = opcode[1] = 0; + + /* HACK: Retrieve instruction opcode */ + if (likely(s->data->datalen >= 2)) { + saa_fread(s->data, s->data->datalen-2, opcode, 2); + } else if (s->data->datalen == 1) { + saa_fread(s->data, 0, opcode+1, 1); + } + + if (opcode[1] == 0xe8 || opcode[1] == 0xe9 || + (opcode[0] == 0x0f && (opcode[1] & 0xf0) == 0x80)) { + /* Direct call, jmp, or jcc */ + reltype = RL_BRANCH; + } } - if (gotload == 0x8B) { - /* Check for MOVQ Opcode -> X86_64_RELOC_GOT_LOAD */ - addr += add_reloc(s, section, offset, RL_GOTLOAD, 4); - } else { - /* X86_64_RELOC_GOT */ - addr += add_reloc(s, section, offset, RL_GOT, 4); + } else if (wrt == macho_gotpcrel_sect) { + reltype = RL_GOT; + + if ((s->flags & S_ATTR_SOME_INSTRUCTIONS) && + s->data->datalen >= 3) { + uint8_t gotload[3]; + + /* HACK: Retrieve instruction opcode */ + saa_fread(s->data, s->data->datalen-3, gotload, 3); + if ((gotload[0] & 0xf8) == 0x48 && + gotload[1] == 0x8b && + (gotload[2] & 0307) == 0005) { + /* movq <reg>,[rel sym wrt ..gotpcrel] */ + reltype = RL_GOTLOAD; + } } } else if (wrt == macho_tlvp_sect) { - addr += add_reloc(s, section, offset, RL_TLV, 4); + reltype = RL_TLV; } else { nasm_error(ERR_NONFATAL, "Mach-O format does not support" " this use of WRT"); - wrt = NO_SEG; /* we can at least _try_ to continue */ + /* continue with RL_REL */ } + addr += add_reloc(s, section, offset, reltype, 4); WRITELONG(p, addr); sect_write(s, mydata, 4); break; |