プログラミングとか色々

プログラミングとかについて色々

アセンブリと仲良くなりたい

アセンブリと仲良くなりたい

この記事は群馬高専アドベントカレンダー2022の22日目の記事になります。

目次

自己紹介

いろんなプログラミング言語に手を出すのと競プロが好きです。 浅くいろんなものに手を出してます。最近は音楽とプラモデルにはまってます。

アセンブリ難しくない?

この頃とても便利な高レベル言語がたくさんあり、アセンブリといった低レベル言語を使う機会はあまりなくなりました。 しかし、弊学J科のマイコンの授業ではアセンブリの読み書きができるようにならなければいけません。 そのうえ学校の実行環境は特殊なソフトとマイコンを使うのであまり手軽ではなく難しいものとなっています。 情報系の学生にとってこのような状況は意外と多いのではないでしょうか

家でもアセンブリを読み書き・実行できると便利だと思いこの記事を書きました。

形式とかアーキテクチャとかについてはまだよく調べられてないので適当ですみません

アセンブリ読みたい

c言語からアセンブリ

gccではc言語からアセンブリの生成ができます。 gccのほかにもzig ccclangでもできるらしいです。 コンパイルオプションとして-Sを追加します。

標準ではAT&T形式アセンブリが生成され、追加でオプションを追加することでAT&T形式intel形式を変えることができるらしいです。

例として、

gcc -S test.c

を実行するとtest.sが生成されます。 このtest.sはこのような内容になっています。

そこそこ長いので折りたたみます

test.cソースコード

int main() {
    return 0;
}

出力結果

    .text
    .def    @feat.00;
    .scl    3;
    .type   0;
    .endef
    .globl  @feat.00
.set @feat.00, 0
    .file   "test.c"
    .def    main;
    .scl    2;
    .type   32;
    .endef
    .globl  main                            # -- Begin function main
    .p2align    4, 0x90
main:                                   # @main
.seh_proc main
# %bb.0:
    pushq   %rbp
    .seh_pushreg %rbp
    subq    $48, %rsp
    .seh_stackalloc 48
    leaq    48(%rsp), %rbp
    .seh_setframe %rbp, 48
    .seh_endprologue
    callq   __main
    movl    $0, -4(%rbp)
    xorl    %eax, %eax
    addq    $48, %rsp
    popq    %rbp
    retq
    .seh_endproc
                                        # -- End function
    .addrsig

実行ファイルからアセンブリ

objdumpコマンドを使用することで実行ファイルからアセンブリの生成ができます。 -dオプションを使うことでdisassembleができます。 windowsでもこのコマンドを使用することができますが、 出力されるアセンブリがとても読みにくいため環境があればlinuxがおすすめです。

Linux 5.15.79.1-microsoft-standard-WSL2 での実行例を下にまとめます。

だいぶ長いので折りたたみます

test.c元のC言語ファイル

int main() {
    return 0;
}

コンパイルして実行ファイルにし、それをディスアセンブルする。

gcc test.c
objdump -d ./a.out

出力結果

./a.out:     file format elf64-x86-64


Disassembly of section .init:

0000000000001000 <_init>:
    1000:       f3 0f 1e fa             endbr64
    1004:       48 83 ec 08             sub    $0x8,%rsp
    1008:       48 8b 05 d9 2f 00 00    mov    0x2fd9(%rip),%rax        # 3fe8 <__gmon_start__@Base>
    100f:       48 85 c0                test   %rax,%rax
    1012:       74 02                   je     1016 <_init+0x16>
    1014:       ff d0                   call   *%rax
    1016:       48 83 c4 08             add    $0x8,%rsp
    101a:       c3                      ret

Disassembly of section .plt:

0000000000001020 <.plt>:
    1020:       ff 35 a2 2f 00 00       push   0x2fa2(%rip)        # 3fc8 <_GLOBAL_OFFSET_TABLE_+0x8>
    1026:       f2 ff 25 a3 2f 00 00    bnd jmp *0x2fa3(%rip)        # 3fd0 <_GLOBAL_OFFSET_TABLE_+0x10>
    102d:       0f 1f 00                nopl   (%rax)

Disassembly of section .plt.got:

0000000000001030 <__cxa_finalize@plt>:
    1030:       f3 0f 1e fa             endbr64
    1034:       f2 ff 25 bd 2f 00 00    bnd jmp *0x2fbd(%rip)        # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
    103b:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

Disassembly of section .text:

0000000000001040 <_start>:
    1040:       f3 0f 1e fa             endbr64
    1044:       31 ed                   xor    %ebp,%ebp
    1046:       49 89 d1                mov    %rdx,%r9
    1049:       5e                      pop    %rsi
    104a:       48 89 e2                mov    %rsp,%rdx
    104d:       48 83 e4 f0             and    $0xfffffffffffffff0,%rsp
    1051:       50                      push   %rax
    1052:       54                      push   %rsp
    1053:       45 31 c0                xor    %r8d,%r8d
    1056:       31 c9                   xor    %ecx,%ecx
    1058:       48 8d 3d ca 00 00 00    lea    0xca(%rip),%rdi        # 1129 <main>
    105f:       ff 15 73 2f 00 00       call   *0x2f73(%rip)        # 3fd8 <__libc_start_main@GLIBC_2.34>
    1065:       f4                      hlt
    1066:       66 2e 0f 1f 84 00 00    cs nopw 0x0(%rax,%rax,1)
    106d:       00 00 00

0000000000001070 <deregister_tm_clones>:
    1070:       48 8d 3d 99 2f 00 00    lea    0x2f99(%rip),%rdi        # 4010 <__TMC_END__>
    1077:       48 8d 05 92 2f 00 00    lea    0x2f92(%rip),%rax        # 4010 <__TMC_END__>
    107e:       48 39 f8                cmp    %rdi,%rax
    1081:       74 15                   je     1098 <deregister_tm_clones+0x28>
    1083:       48 8b 05 56 2f 00 00    mov    0x2f56(%rip),%rax        # 3fe0 <_ITM_deregisterTMCloneTable@Base>
    108a:       48 85 c0                test   %rax,%rax
    108d:       74 09                   je     1098 <deregister_tm_clones+0x28>
    108f:       ff e0                   jmp    *%rax
    1091:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)
    1098:       c3                      ret
    1099:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

00000000000010a0 <register_tm_clones>:
    10a0:       48 8d 3d 69 2f 00 00    lea    0x2f69(%rip),%rdi        # 4010 <__TMC_END__>
    10a7:       48 8d 35 62 2f 00 00    lea    0x2f62(%rip),%rsi        # 4010 <__TMC_END__>
    10ae:       48 29 fe                sub    %rdi,%rsi
    10b1:       48 89 f0                mov    %rsi,%rax
    10b4:       48 c1 ee 3f             shr    $0x3f,%rsi
    10b8:       48 c1 f8 03             sar    $0x3,%rax
    10bc:       48 01 c6                add    %rax,%rsi
    10bf:       48 d1 fe                sar    %rsi
    10c2:       74 14                   je     10d8 <register_tm_clones+0x38>
    10c4:       48 8b 05 25 2f 00 00    mov    0x2f25(%rip),%rax        # 3ff0 <_ITM_registerTMCloneTable@Base>
    10cb:       48 85 c0                test   %rax,%rax
    10ce:       74 08                   je     10d8 <register_tm_clones+0x38>
    10d0:       ff e0                   jmp    *%rax
    10d2:       66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)
    10d8:       c3                      ret
    10d9:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

00000000000010e0 <__do_global_dtors_aux>:
    10e0:       f3 0f 1e fa             endbr64
    10e4:       80 3d 25 2f 00 00 00    cmpb   $0x0,0x2f25(%rip)        # 4010 <__TMC_END__>
    10eb:       75 2b                   jne    1118 <__do_global_dtors_aux+0x38>
    10ed:       55                      push   %rbp
    10ee:       48 83 3d 02 2f 00 00    cmpq   $0x0,0x2f02(%rip)        # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
    10f5:       00
    10f6:       48 89 e5                mov    %rsp,%rbp
    10f9:       74 0c                   je     1107 <__do_global_dtors_aux+0x27>
    10fb:       48 8b 3d 06 2f 00 00    mov    0x2f06(%rip),%rdi        # 4008 <__dso_handle>
    1102:       e8 29 ff ff ff          call   1030 <__cxa_finalize@plt>
    1107:       e8 64 ff ff ff          call   1070 <deregister_tm_clones>
    110c:       c6 05 fd 2e 00 00 01    movb   $0x1,0x2efd(%rip)        # 4010 <__TMC_END__>
    1113:       5d                      pop    %rbp
    1114:       c3                      ret
    1115:       0f 1f 00                nopl   (%rax)
    1118:       c3                      ret
    1119:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

0000000000001120 <frame_dummy>:
    1120:       f3 0f 1e fa             endbr64
    1124:       e9 77 ff ff ff          jmp    10a0 <register_tm_clones>

0000000000001129 <main>:
    1129:       f3 0f 1e fa             endbr64
    112d:       55                      push   %rbp
    112e:       48 89 e5                mov    %rsp,%rbp
    1131:       b8 00 00 00 00          mov    $0x0,%eax
    1136:       5d                      pop    %rbp
    1137:       c3                      ret

Disassembly of section .fini:

0000000000001138 <_fini>:
    1138:       f3 0f 1e fa             endbr64
    113c:       48 83 ec 08             sub    $0x8,%rsp
    1140:       48 83 c4 08             add    $0x8,%rsp
    1144:       c3                      ret

アセンブリ書きたい

gccではアセンブリ.sファイルとして認識し、

gcc test.s

とするとアセンブリファイルから実行ファイルを生成してくれます。

これもgccのほかにもzig ccclangでもできるらしいです。

これは余談なのですが、gccでは.cファイル、.hファイルをコンパイルできるのは有名ですが、ほかのファイルを渡した場合どうなるのでしょう。 そもそもgccccはC Compilerの略ではなく、Compiler Collectionのccらしいです。 そして、公式ホームページによると、

The GNU Compiler Collection includes front ends for C, C++, Objective-C, Fortran, Ada, Go, and D, as well as libraries for these languages (libstdc++,...)

と、いろいろな言語をサポートしているようです。(c言語以外で使ったことないですが、、、)

これもそこそこ長いので折りたたみます

適当にフィボナッチ数列rdi項目を求めるプログラムtest.sを書きました。

.intel_syntax noprefix
.globl main

fib:
    mov rdx, 0
    mov rcx, 1
fib_loop:
    mov rsi, 0
    add rsi, rdx
    add rsi, rcx
    mov rdx, rcx
    mov rcx, rsi
    sub rdi, 1
    cmp rdi, 0
    jne fib_loop
    mov rax, rsi
    ret

main:
    mov rdi, 5
    call fib
    ret
gcc test.s
./a.out

を実行すると生成されたa.outが実行されます。 (windowsならa.exe?) 出力結果は

bash

echo $?

fish

echo $status

powershell

echo $LASTEXITCODE

で見ることができます。

さいごに

アセンブリと仲良くなりましょう!!

次は、「こひむ」さんの「高専プロコン失敗談」です。