summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2016-02-21 21:24:38 -0800
committerH. Peter Anvin <hpa@zytor.com>2016-02-21 21:24:38 -0800
commit95b43676c30011d1e9eeaef3d9487d135260d3c0 (patch)
tree5602fd0aacab7be79f99a5c8136a74266abbbc31
parentec82d7a92b6b36ee82a051ac437d5206971e179b (diff)
parentd4e001db67531894ba402bf04bc44c00c203dc6d (diff)
downloadnasm-95b43676c30011d1e9eeaef3d9487d135260d3c0.tar.gz
Merge branch 'master' into elfmerge
-rwxr-xr-xmisc/tag-release12
-rw-r--r--output/outmacho.c63
-rw-r--r--version2
3 files changed, 56 insertions, 21 deletions
diff --git a/misc/tag-release b/misc/tag-release
index 62e3eba5..9e3a0bd0 100755
--- a/misc/tag-release
+++ b/misc/tag-release
@@ -3,10 +3,9 @@
version=""
repo=""
branch=""
-push=1
+push=0
-for opt in $*
-do
+for opt; do
case "$opt" in
--ver=*)
version=`echo $opt | sed 's/[-a-zA-Z0-9]*=//'`
@@ -17,9 +16,16 @@ do
--branch=*)
branch=`echo $opt | sed 's/[-a-zA-Z0-9]*=//'`
;;
+ --push)
+ push=1
+ ;;
--no-push)
push=0
;;
+ -*)
+ echo "Invalid option: $opt" 1>&2
+ exit 1
+ ;;
*)
version=$opt
;;
diff --git a/output/outmacho.c b/output/outmacho.c
index cd393af6..94465e43 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;
diff --git a/version b/version
index 38e6cc52..ab30d274 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-2.12rc5
+2.12rc6