diff options
author | Peter Johnson <peter@tortall.net> | 2007-09-19 07:47:10 +0000 |
---|---|---|
committer | Peter Johnson <peter@tortall.net> | 2007-09-19 07:47:10 +0000 |
commit | 31ef2e7a52647e34a37a94e7892be52f321dedf9 (patch) | |
tree | 20e847f861e34569337f2697c95f62ba9e6b475d | |
parent | 6dfe4b13fd4c4f971774325870e79da7f057bbfc (diff) | |
download | yasm-31ef2e7a52647e34a37a94e7892be52f321dedf9.tar.gz |
Support NASM's upcoming RIP-relative syntax, with a few differences.
This adds a "default" directive that takes either "rel" or "abs". This
sets whether the default mode for simple displacements is RIP-relative (rel)
or not (abs). The default without a directive is "abs".
Also added is corresponding "rel" and "abs" effective address modifiers
to override whatever default is set:
[rel label] is RIP-relative
[abs label] is not.
In default rel mode, [label] defaults to the former, in default abs mode,
the latter. Also, segment overrides (note difference from NASM below) are
abs regardless of mode, unless explicitly overridden with rel:
[fs:label] is always abs
[rel fs:label] is always rel
However, we have a number of differences from NASM in this handling due to
what I feel to be yasm's more sane handling of [dword ...] and [qword ...].
In yasm, these set the displacement size, rather than the address size; the
latter is set using a a32/a64 prefix. I feel this is more sane as in 64-bit
mode the two can be different in the MovOffs (A0/A1 mov *ax) case.
Also, yasm disables default-rel mode if any segment register is used, not
just FS or GS as NASM currently does.
See modules/arch/x86/tests/riprel1.asm and
modules/arch/x86/tests/riprel2.asm for examples, as well as my recent
posting to the nasm-devel mailing list on SF.
svn path=/trunk/yasm/; revision=1963
-rw-r--r-- | libyasm/insn.h | 6 | ||||
-rw-r--r-- | modules/arch/lc3b/lc3barch.c | 2 | ||||
-rw-r--r-- | modules/arch/x86/tests/Makefile.inc | 5 | ||||
-rw-r--r-- | modules/arch/x86/tests/riprel1.asm | 66 | ||||
-rw-r--r-- | modules/arch/x86/tests/riprel1.hex | 334 | ||||
-rw-r--r-- | modules/arch/x86/tests/riprel2.asm | 110 | ||||
-rw-r--r-- | modules/arch/x86/tests/riprel2.errwarn | 26 | ||||
-rw-r--r-- | modules/arch/x86/tests/riprel2.hex | 708 | ||||
-rw-r--r-- | modules/arch/x86/x86arch.c | 9 | ||||
-rw-r--r-- | modules/arch/x86/x86arch.h | 1 | ||||
-rw-r--r-- | modules/arch/x86/x86bc.c | 2 | ||||
-rw-r--r-- | modules/arch/x86/x86expr.c | 15 | ||||
-rw-r--r-- | modules/arch/x86/x86id.c | 24 | ||||
-rw-r--r-- | modules/parsers/nasm/nasm-parse.c | 66 | ||||
-rw-r--r-- | modules/parsers/nasm/nasm-parser.h | 2 | ||||
-rw-r--r-- | modules/parsers/nasm/nasm-token.re | 3 | ||||
-rw-r--r-- | modules/preprocs/nasm/standard.mac | 4 |
17 files changed, 1370 insertions, 13 deletions
diff --git a/libyasm/insn.h b/libyasm/insn.h index 20977b2c..ea3fe539 100644 --- a/libyasm/insn.h +++ b/libyasm/insn.h @@ -64,6 +64,12 @@ struct yasm_effaddr { * "expr(,1)" (which is definitely an effective address). */ unsigned int strong:1; + + /** 1 if effective address is forced PC-relative. */ + unsigned int pc_rel:1; + + /** 1 if effective address is forced non-PC-relative. */ + unsigned int not_pc_rel:1; }; /** An instruction operand (opaque type). */ diff --git a/modules/arch/lc3b/lc3barch.c b/modules/arch/lc3b/lc3barch.c index e1835d0a..84f188a8 100644 --- a/modules/arch/lc3b/lc3barch.c +++ b/modules/arch/lc3b/lc3barch.c @@ -158,6 +158,8 @@ lc3b_ea_create_expr(yasm_arch *arch, yasm_expr *e) ea->nosplit = 0; ea->strong = 0; ea->segreg = 0; + ea->pc_rel = 0; + ea->not_pc_rel = 0; return ea; } diff --git a/modules/arch/x86/tests/Makefile.inc b/modules/arch/x86/tests/Makefile.inc index c513ad17..67e8b5c6 100644 --- a/modules/arch/x86/tests/Makefile.inc +++ b/modules/arch/x86/tests/Makefile.inc @@ -126,6 +126,11 @@ EXTRA_DIST += modules/arch/x86/tests/rep.asm EXTRA_DIST += modules/arch/x86/tests/rep.hex EXTRA_DIST += modules/arch/x86/tests/ret.asm EXTRA_DIST += modules/arch/x86/tests/ret.hex +EXTRA_DIST += modules/arch/x86/tests/riprel1.asm +EXTRA_DIST += modules/arch/x86/tests/riprel1.hex +EXTRA_DIST += modules/arch/x86/tests/riprel2.asm +EXTRA_DIST += modules/arch/x86/tests/riprel2.errwarn +EXTRA_DIST += modules/arch/x86/tests/riprel2.hex EXTRA_DIST += modules/arch/x86/tests/segmov.asm EXTRA_DIST += modules/arch/x86/tests/segmov.hex EXTRA_DIST += modules/arch/x86/tests/shift.asm diff --git a/modules/arch/x86/tests/riprel1.asm b/modules/arch/x86/tests/riprel1.asm new file mode 100644 index 00000000..b1fdbecb --- /dev/null +++ b/modules/arch/x86/tests/riprel1.asm @@ -0,0 +1,66 @@ +bits 64 +val: +default abs + +mov rax, val ; 32-bit imm +mov rax, dword val ; 32-bit imm +mov rax, qword val ; 64-bit imm + +mov rbx, val ; 32-bit imm +mov rbx, dword val ; 32-bit imm +mov rbx, qword val ; 64-bit imm + +mov rax, [val] ; 48 8b ... (32-bit disp) +mov rax, [dword val] ; 48 8b ... (32-bit disp) +mov rax, [qword val] ; 48 a1 ... (64-bit disp) +a32 mov rax, [val] ; 67 48 a1 ... (32-bit disp) +a32 mov rax, [dword val] ; 67 48 a1 ... (32-bit disp) +a32 mov rax, [qword val] ; 67 48 a1 ... (32-bit disp) + ; [this one is debatable on correctness, + ; I chose in yasm to make a32 override] +a64 mov rax, [val] ; 48 8b ... (32-bit disp) +a64 mov rax, [dword val] ; 48 8b ... (32-bit disp) +a64 mov rax, [qword val] ; 48 a1 ... (64-bit disp) + +mov rbx, [val] ; 48 8b ... (32-bit disp) +mov rbx, [dword val] ; 48 8b ... (32-bit disp) +;mov rbx, [qword val] ; illegal (can't have 64-bit disp) +a32 mov rbx, [val] ; 67 48 8b ... (32-bit disp) +a32 mov rbx, [dword val] ; 67 48 8b ... (32-bit disp) +;a32 mov rbx, [qword val] ; illegal (can't have 64-bit disp) +a64 mov rbx, [val] ; 48 8b ... (32-bit disp) +a64 mov rbx, [dword val] ; 48 8b ... (32-bit disp) +;a64 mov rbx, [qword val] ; illegal (can't have 64-bit disp) + +default rel + +mov rax, val ; 32-bit imm +mov rax, dword val ; 32-bit imm +mov rax, qword val ; 64-bit imm + +mov rbx, val ; 32-bit imm +mov rbx, dword val ; 32-bit imm +mov rbx, qword val ; 64-bit imm + +mov rax, [val] ; 48 8b ... (32-bit disp, RIP-rel) +mov rax, [dword val] ; 48 8b ... (32-bit disp, RIP-rel) +mov rax, [qword val] ; 48 a1 ... (64-bit disp, ABS) +a32 mov rax, [val] ; 67 48 8b ... (32-bit disp, RIP-rel) +a32 mov rax, [dword val] ; 67 48 8b ... (32-bit disp, RIP-rel) +a32 mov rax, [qword val] ; 67 48 a1 ... (32-bit disp, ABS) + ; [this one is debatable on correctness, + ; I chose in yasm to make a32 override] +a64 mov rax, [val] ; 48 8b ... (32-bit disp, RIP-rel) +a64 mov rax, [dword val] ; 48 8b ... (32-bit disp, RIP-rel) +a64 mov rax, [qword val] ; 48 a1 ... (64-bit disp, ABS) + +mov rbx, [val] ; 48 8b ... (32-bit disp, RIP-rel) +mov rbx, [dword val] ; 48 8b ... (32-bit disp, RIP-rel) +;mov rbx, [qword val] ; illegal (can't have 64-bit disp) +a32 mov rbx, [val] ; 67 48 8b ... (32-bit disp, RIP-rel) +a32 mov rbx, [dword val] ; 67 48 8b ... (32-bit disp, RIP-rel) +;a32 mov rbx, [qword val] ; illegal (can't have 64-bit disp) +a64 mov rbx, [val] ; 48 8b ... (32-bit disp, RIP-rel) +a64 mov rbx, [dword val] ; 48 8b ... (32-bit disp, RIP-rel) +;a64 mov rbx, [qword val] ; illegal (can't have 64-bit disp) + diff --git a/modules/arch/x86/tests/riprel1.hex b/modules/arch/x86/tests/riprel1.hex new file mode 100644 index 00000000..78f28bff --- /dev/null +++ b/modules/arch/x86/tests/riprel1.hex @@ -0,0 +1,334 @@ +48 +c7 +c0 +00 +00 +00 +00 +48 +c7 +c0 +00 +00 +00 +00 +48 +b8 +00 +00 +00 +00 +00 +00 +00 +00 +48 +c7 +c3 +00 +00 +00 +00 +48 +c7 +c3 +00 +00 +00 +00 +48 +bb +00 +00 +00 +00 +00 +00 +00 +00 +48 +8b +04 +25 +00 +00 +00 +00 +48 +8b +04 +25 +00 +00 +00 +00 +48 +a1 +00 +00 +00 +00 +00 +00 +00 +00 +67 +48 +a1 +00 +00 +00 +00 +67 +48 +a1 +00 +00 +00 +00 +67 +48 +a1 +00 +00 +00 +00 +48 +8b +04 +25 +00 +00 +00 +00 +48 +8b +04 +25 +00 +00 +00 +00 +48 +a1 +00 +00 +00 +00 +00 +00 +00 +00 +48 +8b +1c +25 +00 +00 +00 +00 +48 +8b +1c +25 +00 +00 +00 +00 +67 +48 +8b +1c +25 +00 +00 +00 +00 +67 +48 +8b +1c +25 +00 +00 +00 +00 +48 +8b +1c +25 +00 +00 +00 +00 +48 +8b +1c +25 +00 +00 +00 +00 +48 +c7 +c0 +00 +00 +00 +00 +48 +c7 +c0 +00 +00 +00 +00 +48 +b8 +00 +00 +00 +00 +00 +00 +00 +00 +48 +c7 +c3 +00 +00 +00 +00 +48 +c7 +c3 +00 +00 +00 +00 +48 +bb +00 +00 +00 +00 +00 +00 +00 +00 +48 +8b +05 +1e +ff +ff +ff +48 +8b +05 +17 +ff +ff +ff +48 +a1 +00 +00 +00 +00 +00 +00 +00 +00 +67 +48 +8b +05 +05 +ff +ff +ff +67 +48 +8b +05 +fd +fe +ff +ff +67 +48 +a1 +00 +00 +00 +00 +48 +8b +05 +ef +fe +ff +ff +48 +8b +05 +e8 +fe +ff +ff +48 +a1 +00 +00 +00 +00 +00 +00 +00 +00 +48 +8b +1d +d7 +fe +ff +ff +48 +8b +1d +d0 +fe +ff +ff +67 +48 +8b +1d +c8 +fe +ff +ff +67 +48 +8b +1d +c0 +fe +ff +ff +48 +8b +1d +b9 +fe +ff +ff +48 +8b +1d +b2 +fe +ff +ff diff --git a/modules/arch/x86/tests/riprel2.asm b/modules/arch/x86/tests/riprel2.asm new file mode 100644 index 00000000..813d9e5a --- /dev/null +++ b/modules/arch/x86/tests/riprel2.asm @@ -0,0 +1,110 @@ + bits 64 + + default abs ; default abs, except for explicit rel + + mov rax,[foo] + mov rax,[qword 123456789abcdef0h] + mov rbx,[foo] + mov rax,[dword foo] + mov rbx,[dword foo] + mov rax,[qword foo] + mov rax,[rel foo] ; rel + mov rbx,[rel foo] ; rel + mov rax,[rel dword foo] ; rel + ;mov rax,[rel qword foo] ; illegal + mov rax,[abs foo] + mov rbx,[abs foo] + mov rax,[abs dword foo] + mov rax,[abs qword foo] + + mov rax,[es:foo] + mov rax,[qword es:123456789abcdef0h] + mov rbx,[es:foo] + mov rax,[dword es:foo] + mov rbx,[dword es:foo] + mov rax,[qword es:foo] + mov rax,[rel es:foo] ; rel + mov rbx,[rel es:foo] ; rel + mov rax,[rel dword es:foo] ; rel + ;mov rax,[rel qword es:foo] ; illegal + mov rax,[abs es:foo] + mov rbx,[abs es:foo] + mov rax,[abs dword es:foo] + mov rax,[abs qword es:foo] + + mov rax,[fs:foo] + mov rax,[qword fs:123456789abcdef0h] + mov rbx,[fs:foo] + mov rax,[dword fs:foo] + mov rbx,[dword fs:foo] + mov rax,[qword fs:foo] + mov rax,[rel fs:foo] ; rel + mov rbx,[rel fs:foo] ; rel + mov rax,[rel dword fs:foo] ; rel + ;mov rax,[rel qword fs:foo] ; illegal + mov rax,[abs fs:foo] + mov rbx,[abs fs:foo] + mov rax,[abs dword fs:foo] + mov rax,[abs qword fs:foo] + + mov rax,[rbx] + mov rax,[rel rbx] + mov rax,[abs rbx] + + default rel + + ; all of these are default rel, except for 64-bit displacements + mov rax,[foo] + mov rax,[qword 123456789abcdef0h] ; abs + mov rbx,[foo] + mov rax,[dword foo] + mov rbx,[dword foo] + mov rax,[qword foo] ; abs + mov rax,[rel foo] + mov rbx,[rel foo] + mov rax,[rel dword foo] + ;mov rax,[rel qword foo] ; illegal + mov rax,[abs foo] + mov rbx,[abs foo] + mov rax,[abs dword foo] + mov rax,[abs qword foo] + + ; all of these are abs due to es:, except for explicit rel + mov rax,[es:foo] + mov rax,[qword es:123456789abcdef0h] + mov rbx,[es:foo] + mov rax,[dword es:foo] + mov rbx,[dword es:foo] + mov rax,[qword es:foo] + mov rax,[rel es:foo] ; rel + mov rbx,[rel es:foo] ; rel + mov rax,[rel dword es:foo] ; rel + ;mov rax,[rel qword es:foo] ; illegal + mov rax,[abs es:foo] + mov rbx,[abs es:foo] + mov rax,[abs dword es:foo] + mov rax,[abs qword es:foo] + + ; all of these are abs due to fs:, except for explicit rel + mov rax,[fs:foo] + mov rax,[qword fs:123456789abcdef0h] + mov rbx,[fs:foo] + mov rax,[dword fs:foo] + mov rbx,[dword fs:foo] + mov rax,[qword fs:foo] + mov rax,[rel fs:foo] ; rel + mov rbx,[rel fs:foo] ; rel + mov rax,[rel dword fs:foo] ; rel + ;mov rax,[rel qword fs:foo] ; illegal + mov rax,[abs fs:foo] + mov rbx,[abs fs:foo] + mov rax,[abs dword fs:foo] + mov rax,[abs qword fs:foo] + + mov rax,[rbx] + mov rax,[rel rbx] + mov rax,[abs rbx] + + section .data +foo equ $ + diff --git a/modules/arch/x86/tests/riprel2.errwarn b/modules/arch/x86/tests/riprel2.errwarn new file mode 100644 index 00000000..b219dc7e --- /dev/null +++ b/modules/arch/x86/tests/riprel2.errwarn @@ -0,0 +1,26 @@ +-:20: warning: `es' segment register ignored in 64-bit mode +-:21: warning: `es' segment register ignored in 64-bit mode +-:22: warning: `es' segment register ignored in 64-bit mode +-:23: warning: `es' segment register ignored in 64-bit mode +-:24: warning: `es' segment register ignored in 64-bit mode +-:25: warning: `es' segment register ignored in 64-bit mode +-:26: warning: `es' segment register ignored in 64-bit mode +-:27: warning: `es' segment register ignored in 64-bit mode +-:28: warning: `es' segment register ignored in 64-bit mode +-:30: warning: `es' segment register ignored in 64-bit mode +-:31: warning: `es' segment register ignored in 64-bit mode +-:32: warning: `es' segment register ignored in 64-bit mode +-:33: warning: `es' segment register ignored in 64-bit mode +-:73: warning: `es' segment register ignored in 64-bit mode +-:74: warning: `es' segment register ignored in 64-bit mode +-:75: warning: `es' segment register ignored in 64-bit mode +-:76: warning: `es' segment register ignored in 64-bit mode +-:77: warning: `es' segment register ignored in 64-bit mode +-:78: warning: `es' segment register ignored in 64-bit mode +-:79: warning: `es' segment register ignored in 64-bit mode +-:80: warning: `es' segment register ignored in 64-bit mode +-:81: warning: `es' segment register ignored in 64-bit mode +-:83: warning: `es' segment register ignored in 64-bit mode +-:84: warning: `es' segment register ignored in 64-bit mode +-:85: warning: `es' segment register ignored in 64-bit mode +-:86: warning: `es' segment register ignored in 64-bit mode diff --git a/modules/arch/x86/tests/riprel2.hex b/modules/arch/x86/tests/riprel2.hex new file mode 100644 index 00000000..5d9a9183 --- /dev/null +++ b/modules/arch/x86/tests/riprel2.hex @@ -0,0 +1,708 @@ +48 +8b +04 +25 +c4 +02 +00 +00 +48 +a1 +f0 +de +bc +9a +78 +56 +34 +12 +48 +8b +1c +25 +c4 +02 +00 +00 +48 +8b +04 +25 +c4 +02 +00 +00 +48 +8b +1c +25 +c4 +02 +00 +00 +48 +a1 +c4 +02 +00 +00 +00 +00 +00 +00 +48 +8b +05 +89 +02 +00 +00 +48 +8b +1d +82 +02 +00 +00 +48 +8b +05 +7b +02 +00 +00 +48 +8b +04 +25 +c4 +02 +00 +00 +48 +8b +1c +25 +c4 +02 +00 +00 +48 +8b +04 +25 +c4 +02 +00 +00 +48 +a1 +c4 +02 +00 +00 +00 +00 +00 +00 +26 +48 +8b +04 +25 +c4 +02 +00 +00 +26 +48 +a1 +f0 +de +bc +9a +78 +56 +34 +12 +26 +48 +8b +1c +25 +c4 +02 +00 +00 +26 +48 +8b +04 +25 +c4 +02 +00 +00 +26 +48 +8b +1c +25 +c4 +02 +00 +00 +26 +48 +a1 +c4 +02 +00 +00 +00 +00 +00 +00 +26 +48 +8b +05 +17 +02 +00 +00 +26 +48 +8b +1d +0f +02 +00 +00 +26 +48 +8b +05 +07 +02 +00 +00 +26 +48 +8b +04 +25 +c4 +02 +00 +00 +26 +48 +8b +1c +25 +c4 +02 +00 +00 +26 +48 +8b +04 +25 +c4 +02 +00 +00 +26 +48 +a1 +c4 +02 +00 +00 +00 +00 +00 +00 +64 +48 +8b +04 +25 +c4 +02 +00 +00 +64 +48 +a1 +f0 +de +bc +9a +78 +56 +34 +12 +64 +48 +8b +1c +25 +c4 +02 +00 +00 +64 +48 +8b +04 +25 +c4 +02 +00 +00 +64 +48 +8b +1c +25 +c4 +02 +00 +00 +64 +48 +a1 +c4 +02 +00 +00 +00 +00 +00 +00 +64 +48 +8b +05 +9f +01 +00 +00 +64 +48 +8b +1d +97 +01 +00 +00 +64 +48 +8b +05 +8f +01 +00 +00 +64 +48 +8b +04 +25 +c4 +02 +00 +00 +64 +48 +8b +1c +25 +c4 +02 +00 +00 +64 +48 +8b +04 +25 +c4 +02 +00 +00 +64 +48 +a1 +c4 +02 +00 +00 +00 +00 +00 +00 +48 +8b +03 +48 +8b +03 +48 +8b +03 +48 +8b +05 +59 +01 +00 +00 +48 +a1 +f0 +de +bc +9a +78 +56 +34 +12 +48 +8b +1d +48 +01 +00 +00 +48 +8b +05 +41 +01 +00 +00 +48 +8b +1d +3a +01 +00 +00 +48 +a1 +c4 +02 +00 +00 +00 +00 +00 +00 +48 +8b +05 +29 +01 +00 +00 +48 +8b +1d +22 +01 +00 +00 +48 +8b +05 +1b +01 +00 +00 +48 +8b +04 +25 +c4 +02 +00 +00 +48 +8b +1c +25 +c4 +02 +00 +00 +48 +8b +04 +25 +c4 +02 +00 +00 +48 +a1 +c4 +02 +00 +00 +00 +00 +00 +00 +26 +48 +8b +04 +25 +c4 +02 +00 +00 +26 +48 +a1 +f0 +de +bc +9a +78 +56 +34 +12 +26 +48 +8b +1c +25 +c4 +02 +00 +00 +26 +48 +8b +04 +25 +c4 +02 +00 +00 +26 +48 +8b +1c +25 +c4 +02 +00 +00 +26 +48 +a1 +c4 +02 +00 +00 +00 +00 +00 +00 +26 +48 +8b +05 +b7 +00 +00 +00 +26 +48 +8b +1d +af +00 +00 +00 +26 +48 +8b +05 +a7 +00 +00 +00 +26 +48 +8b +04 +25 +c4 +02 +00 +00 +26 +48 +8b +1c +25 +c4 +02 +00 +00 +26 +48 +8b +04 +25 +c4 +02 +00 +00 +26 +48 +a1 +c4 +02 +00 +00 +00 +00 +00 +00 +64 +48 +8b +04 +25 +c4 +02 +00 +00 +64 +48 +a1 +f0 +de +bc +9a +78 +56 +34 +12 +64 +48 +8b +1c +25 +c4 +02 +00 +00 +64 +48 +8b +04 +25 +c4 +02 +00 +00 +64 +48 +8b +1c +25 +c4 +02 +00 +00 +64 +48 +a1 +c4 +02 +00 +00 +00 +00 +00 +00 +64 +48 +8b +05 +3f +00 +00 +00 +64 +48 +8b +1d +37 +00 +00 +00 +64 +48 +8b +05 +2f +00 +00 +00 +64 +48 +8b +04 +25 +c4 +02 +00 +00 +64 +48 +8b +1c +25 +c4 +02 +00 +00 +64 +48 +8b +04 +25 +c4 +02 +00 +00 +64 +48 +a1 +c4 +02 +00 +00 +00 +00 +00 +00 +48 +8b +03 +48 +8b +03 +48 +8b +03 diff --git a/modules/arch/x86/x86arch.c b/modules/arch/x86/x86arch.c index d410ac0e..5b8ad700 100644 --- a/modules/arch/x86/x86arch.c +++ b/modules/arch/x86/x86arch.c @@ -67,6 +67,7 @@ x86_create(const char *machine, const char *parser, arch_x86->amd64_machine = amd64_machine; arch_x86->mode_bits = 0; arch_x86->force_strict = 0; + arch_x86->default_rel = 0; if (yasm__strcasecmp(parser, "nasm") == 0) arch_x86->parser = X86_PARSER_NASM; @@ -123,7 +124,13 @@ x86_set_var(yasm_arch *arch, const char *var, unsigned long val) arch_x86->mode_bits = (unsigned int)val; else if (yasm__strcasecmp(var, "force_strict") == 0) arch_x86->force_strict = (unsigned int)val; - else + else if (yasm__strcasecmp(var, "default_rel") == 0) { + if (arch_x86->mode_bits != 64) + yasm_warn_set(YASM_WARN_GENERAL, + N_("ignoring default rel in non-64-bit mode")); + else + arch_x86->default_rel = (unsigned int)val; + } else return 1; return 0; } diff --git a/modules/arch/x86/x86arch.h b/modules/arch/x86/x86arch.h index 705933c0..b5c0f091 100644 --- a/modules/arch/x86/x86arch.h +++ b/modules/arch/x86/x86arch.h @@ -87,6 +87,7 @@ typedef struct yasm_arch_x86 { } parser; unsigned int mode_bits; unsigned int force_strict; + unsigned int default_rel; } yasm_arch_x86; /* 0-15 (low 4 bits) used for register number, stored in same data area. diff --git a/modules/arch/x86/x86bc.c b/modules/arch/x86/x86bc.c index 4319318b..f3717bf7 100644 --- a/modules/arch/x86/x86bc.c +++ b/modules/arch/x86/x86bc.c @@ -190,6 +190,8 @@ ea_create(void) x86_ea->ea.nosplit = 0; x86_ea->ea.strong = 0; x86_ea->ea.segreg = 0; + x86_ea->ea.pc_rel = 0; + x86_ea->ea.not_pc_rel = 0; x86_ea->modrm = 0; x86_ea->valid_modrm = 0; x86_ea->need_modrm = 0; diff --git a/modules/arch/x86/x86expr.c b/modules/arch/x86/x86expr.c index eb145e7a..6358bff1 100644 --- a/modules/arch/x86/x86expr.c +++ b/modules/arch/x86/x86expr.c @@ -636,6 +636,12 @@ yasm_x86__expr_checkea(x86_effaddr *x86_ea, unsigned char *addrsize, return 1; } + if (x86_ea->ea.pc_rel && bits != 64) { + yasm_warn_set(YASM_WARN_GENERAL, + N_("RIP-relative directive ignored in non-64-bit mode")); + x86_ea->ea.pc_rel = 0; + } + reg3264_data.regs = reg3264mult; reg3264_data.bits = bits; reg3264_data.addrsize = *addrsize; @@ -755,6 +761,15 @@ yasm_x86__expr_checkea(x86_effaddr *x86_ea, unsigned char *addrsize, * (optional) SIB bytes. */ + /* If we're supposed to be RIP-relative and there's no register + * usage, change to RIP-relative. + */ + if (basereg == REG3264_NONE && indexreg == REG3264_NONE && + x86_ea->ea.pc_rel) { + basereg = REG64_RIP; + yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1); + } + /* First determine R/M (Mod is later determined from disp size) */ x86_ea->need_modrm = 1; /* we always need ModRM */ if (basereg == REG3264_NONE && indexreg == REG3264_NONE) { diff --git a/modules/arch/x86/x86id.c b/modules/arch/x86/x86id.c index 739c8679..59e74aed 100644 --- a/modules/arch/x86/x86id.c +++ b/modules/arch/x86/x86id.c @@ -301,6 +301,9 @@ typedef struct x86_id_insn { /* Strict forced setting at the time of parsing the instruction */ unsigned int force_strict:1; + + /* Default rel setting at the time of parsing the instruction */ + unsigned int default_rel:1; } x86_id_insn; static void x86_id_insn_destroy(void *contents); @@ -764,7 +767,10 @@ x86_find_match(x86_id_insn *id_insn, yasm_insn_operand **ops, case OPT_MemOffs: if (op->type != YASM_INSN__OPERAND_MEMORY || yasm_expr__contains(op->data.ea->disp.abs, - YASM_EXPR_REG)) + YASM_EXPR_REG) || + op->data.ea->pc_rel || + (!op->data.ea->not_pc_rel && id_insn->default_rel && + op->data.ea->disp.size != 64)) mismatch = 1; break; case OPT_Imm1: @@ -1170,6 +1176,13 @@ x86_id_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) if (info_ops[i].type == OPT_MemOffs) /* Special-case for MOV MemOffs instruction */ yasm_x86__ea_set_disponly(insn->x86_ea); + else if (id_insn->default_rel && + !op->data.ea->not_pc_rel && + op->data.ea->segreg == 0 && + !yasm_expr__contains( + op->data.ea->disp.abs, YASM_EXPR_REG)) + /* Enable default PC-rel if no regs/segregs */ + insn->x86_ea->ea.pc_rel = 1; break; case YASM_INSN__OPERAND_IMM: insn->x86_ea = @@ -1351,8 +1364,12 @@ x86_id_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) * short mov instructions if a 32-bit address override is applied in * 64-bit mode to an EA of just an offset (no registers) and the * target register is al/ax/eax/rax. + * + * We don't want to do this if we're in default rel mode. */ - if (insn->common.mode_bits == 64 && insn->common.addrsize == 32 && + if (!id_insn->default_rel && + insn->common.mode_bits == 64 && + insn->common.addrsize == 32 && (!insn->x86_ea->ea.disp.abs || !yasm_expr__contains(insn->x86_ea->ea.disp.abs, YASM_EXPR_REG))) { @@ -1577,6 +1594,7 @@ yasm_x86__parse_check_insnprefix(yasm_arch *arch, const char *id, id_insn->suffix = 0; id_insn->parser = arch_x86->parser; id_insn->force_strict = arch_x86->force_strict != 0; + id_insn->default_rel = arch_x86->default_rel != 0; *bc = yasm_bc_create_common(&x86_id_insn_callback, id_insn, line); return YASM_ARCH_INSN; } @@ -1608,6 +1626,7 @@ yasm_x86__parse_check_insnprefix(yasm_arch *arch, const char *id, id_insn->suffix = pdata->flags; id_insn->parser = arch_x86->parser; id_insn->force_strict = arch_x86->force_strict != 0; + id_insn->default_rel = arch_x86->default_rel != 0; *bc = yasm_bc_create_common(&x86_id_insn_callback, id_insn, line); return YASM_ARCH_INSN; } else { @@ -1670,6 +1689,7 @@ yasm_x86__create_empty_insn(yasm_arch *arch, unsigned long line) id_insn->suffix = 0; id_insn->parser = arch_x86->parser; id_insn->force_strict = arch_x86->force_strict != 0; + id_insn->default_rel = arch_x86->default_rel != 0; return yasm_bc_create_common(&x86_id_insn_callback, id_insn, line); } diff --git a/modules/parsers/nasm/nasm-parse.c b/modules/parsers/nasm/nasm-parse.c index b449dd1c..b3927e03 100644 --- a/modules/parsers/nasm/nasm-parse.c +++ b/modules/parsers/nasm/nasm-parse.c @@ -755,8 +755,11 @@ parse_memaddr(yasm_parser_nasm *parser_nasm) } get_next_token(); ea = parse_memaddr(parser_nasm); - if (ea) + if (ea) { yasm_ea_set_segreg(ea, segreg); + ea->pc_rel = 0; + ea->not_pc_rel = 1; + } return ea; } case SIZE_OVERRIDE: @@ -774,6 +777,22 @@ parse_memaddr(yasm_parser_nasm *parser_nasm) if (ea) ea->nosplit = 1; return ea; + case REL: + get_next_token(); + ea = parse_memaddr(parser_nasm); + if (ea) { + ea->pc_rel = 1; + ea->not_pc_rel = 0; + } + return ea; + case ABS: + get_next_token(); + ea = parse_memaddr(parser_nasm); + if (ea) { + ea->pc_rel = 0; + ea->not_pc_rel = 1; + } + return ea; default: { yasm_expr *e = parse_expr(parser_nasm, NORM_EXPR); @@ -1131,15 +1150,21 @@ nasm_parser_directive(yasm_parser_nasm *parser_nasm, const char *name, objext_valparams, line)) ; else if (yasm__strcasecmp(name, "absolute") == 0) { - vp = yasm_vps_first(valparams); - if (parser_nasm->absstart) - yasm_expr_destroy(parser_nasm->absstart); - if (parser_nasm->abspos) - yasm_expr_destroy(parser_nasm->abspos); - parser_nasm->absstart = yasm_vp_expr(vp, p_object->symtab, line); - parser_nasm->abspos = yasm_expr_copy(parser_nasm->absstart); - cursect = NULL; - parser_nasm->prev_bc = NULL; + if (!valparams) { + yasm_error_set(YASM_ERROR_SYNTAX, + N_("directive `%s' requires an argument"), + "absolute"); + } else { + vp = yasm_vps_first(valparams); + if (parser_nasm->absstart) + yasm_expr_destroy(parser_nasm->absstart); + if (parser_nasm->abspos) + yasm_expr_destroy(parser_nasm->abspos); + parser_nasm->absstart = yasm_vp_expr(vp, p_object->symtab, line); + parser_nasm->abspos = yasm_expr_copy(parser_nasm->absstart); + cursect = NULL; + parser_nasm->prev_bc = NULL; + } } else if (yasm__strcasecmp(name, "align") == 0) { /* Really, we shouldn't end up with an align directive in an absolute * section (as it's supposed to be only used for nop fill), but handle @@ -1166,6 +1191,27 @@ nasm_parser_directive(yasm_parser_nasm *parser_nasm, const char *name, N_("directive `%s' requires an argument"), "align"); } else dir_align(p_object, valparams, objext_valparams, line); + } else if (yasm__strcasecmp(name, "default") == 0) { + if (!valparams) + ; + else { + vp = yasm_vps_first(valparams); + while (vp) { + const char *id = yasm_vp_id(vp); + if (id) { + if (yasm__strcasecmp(id, "rel") == 0) + yasm_arch_set_var(p_object->arch, "default_rel", 1); + else if (yasm__strcasecmp(id, "abs") == 0) + yasm_arch_set_var(p_object->arch, "default_rel", 0); + else + yasm_error_set(YASM_ERROR_SYNTAX, + N_("unrecognized default `%s'"), id); + } else + yasm_error_set(YASM_ERROR_SYNTAX, + N_("unrecognized default value")); + vp = yasm_vps_next(vp); + } + } } else yasm_error_set(YASM_ERROR_SYNTAX, N_("unrecognized directive `%s'"), name); diff --git a/modules/parsers/nasm/nasm-parser.h b/modules/parsers/nasm/nasm-parser.h index a2671559..4c8de413 100644 --- a/modules/parsers/nasm/nasm-parser.h +++ b/modules/parsers/nasm/nasm-parser.h @@ -45,6 +45,8 @@ enum tokentype { TIMES, SEG, WRT, + ABS, + REL, NOSPLIT, STRICT, INSN, diff --git a/modules/parsers/nasm/nasm-token.re b/modules/parsers/nasm/nasm-token.re index 2e0f3076..cfaad6d5 100644 --- a/modules/parsers/nasm/nasm-token.re +++ b/modules/parsers/nasm/nasm-token.re @@ -315,6 +315,9 @@ scan: 'seg' { RETURN(SEG); } 'wrt' { RETURN(WRT); } + 'abs' { RETURN(ABS); } + 'rel' { RETURN(REL); } + 'nosplit' { RETURN(NOSPLIT); } 'strict' { RETURN(STRICT); } diff --git a/modules/preprocs/nasm/standard.mac b/modules/preprocs/nasm/standard.mac index 6d285d9e..6efd3c84 100644 --- a/modules/preprocs/nasm/standard.mac +++ b/modules/preprocs/nasm/standard.mac @@ -114,6 +114,10 @@ __SECT__ [cpu %1] %endmacro +%imacro default 1+.nolist +[default %1] +%endmacro + ; NASM compatibility shim %define __OUTPUT_FORMAT__ __YASM_OBJFMT__ |