LoginSignup
1
1

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
11

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