1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

レジスタ指定でアドレスジャンプさせてみる

Last updated at Posted at 2019-01-20

Windows 10(64bit版)のClangでアセンブラコードを書いてみましたという話です。

Clangにおけるアセンブラコード

GCC互換です。つまりclangにGASのソースコードを渡すとコンパイルすることができます。また、clangにclang -S hoge.cなどと書いてコンパイルするとclangでディスアセンブルしたコード(.s)が得られます。つまりこいつに適当なCの関数を与えてやってGASの書き方を学べばClang用アセンブラコードを書くことができます。

アセンブラプログラミングはそんなに楽じゃない

  • ラベルの値をレジスタに代入することができません。ラベルの値はアドレス値ですが、アドレス値はプログラムがロードされるときに決定されるのでラベルのアドレス値を静的領域に置いてやる必要があります。レジスタにラベルの値を読ませるときは、代わりに静的領域のデータを読んでやります。 (2019.1.24 追記 RIPレジスタ(プログラムカウンタ)の間接アドレッシングを使えば簡単に実現できます。これは@fujitanozomuさんの再帰的な関数hogeのディスアセンブルによって示されていますが私はすぐにそのことに気が付くことができませんでした)

  • ラベル同士の引き算ができない。なぜ!?すれよ!!!なぜか分かりませんがGASだとできないようです(NASMだとできるのかも…)。ラベル同士の引き算をしてくれると64bitのアドレス値を16bit以内に圧縮することができます。今回はそれを試みましたが失敗しました。 16bitイミディエイトへの代入はできないが16bitの静的領域への代入は可能 (2019.1.23 @fujitanozomuさんのご指摘により修正)

作成したコード

作成したコードを示します。

test1.c
# include <stdio.h>

extern void proc1(void); // proc1.sで定義されている
extern long long int debug;

int main() {
    printf("start program\n");
    proc1();
    printf("end program\n");
    return 0;
}
proc1.s
#
# proc1.s
#

	.text
	.intel_syntax noprefix

# proc1
	.globl proc1
	.p2align	4, 0x90
proc1:
.seh_proc proc1
	push	rax
	push	rbx
	sub	rsp, 40
	.seh_stackalloc 40
	.seh_endprologue
	xor	rax, rax
	mov	ax, word ptr [rip + toOffset]
	add	rax, qword ptr [rip + fromAddress]
	jmp	rax
from:

	.p2align 8, 0x00 # 失敗する命令列
to:
	add	rsp, 40
	pop	rbx
	pop	rax
	ret
	.seh_handlerdata
	.text
	.seh_endproc
	
	.bss
	.data
fromAddress:
	.quad	from
toOffset:
	.word	to - from

ビルドコマンド

clang test1.c proc1.s -o test1.exe

実行結果

start program
end program

より簡約したバージョン (2019.1.24 追記)

下記コメントのhoge関数を-masm=intelオプションでディスアセンブルするとlea [rip + hoge]が得られます。従ってproc1.sのコードはproc1b.sのように簡約することができます。

proc1b.s
#
# proc1b.s
#

	.text
	.intel_syntax noprefix

# proc1
	.globl proc1
	.p2align	4, 0x90
proc1:
.seh_proc proc1
	push	rax
	sub	rsp, 40
	.seh_stackalloc 40
	.seh_endprologue
	lea	rax, [rip + to]
	jmp	rax

	.p2align 8, 0x00 # 失敗する命令列
to:
	add	rsp, 40
	pop	rax
	ret
	.seh_handlerdata
	.text
	.seh_endproc
	
	.bss
	.data

静的領域ではラベル同士の演算を行うことはできるのですが、オペランドにではできないようです。たとえばlea rax, [rip + to - from]はエラーになります。

1
1
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?