アセンブリ言語入門 - tuppy5/programing GitHub Wiki

組み込み技術者のためのアセンブリ言語入門

(0) はじめに

  • 「アセンブリ言語(assemble language」を「アセンブラ」と呼ぶ場合があるが、アセンブラは本来アセンブリ言語をコンパイルするプログラムを指していることに注意しよう。

  • アーキテクチャはARMv7-Aを対象とする。

​ ARMアセンブリ言語を実機動作させるには、

​ - ARM版 Apple PC

​ - Raspberry PiなどのSBC(Single Board Computer)

​ - Cortex-M搭載マイコンボード(STmicro Nucleo 等)

等の方法がある、Windows PC上で動作させるためにWSL2/Ubuntu/QEMU(userモード)を利用する。

https://ja.wikipedia.org/wiki/QEMU

 本文書ではWin10/WSL2/Ubuntu20.04上で実行結果を確認している。

  • QEMUにはSystem Mode/User Modeがあるが、本文書の目的のためにはより軽いUser Modeを使用する。

https://azeria-labs.com/arm-on-x86-qemu-user/

(1) バイナリ入門

gccを使用してC言語のソースコードをコンパイルしてみる

#include <stdio.h>
int main() {
    printf("Hello\n");
    return 0;
}

gccではオプション無しでは、直接実行ファイルが生成されるが、内部では下記のように複数の手順が実行されている。個別の処理はコンパイルオプションを使用することで実行が可能。

.c (C言語ソース) ↓ コンパイル: gcc -c .s(アセンブリ言語ソース) ↓ アセンブラ gcc -S .o (オブジェクトファイル) ↓ リンカ  ld 実行ファイル

gccでは初めにプリプロセッサが実行される

#define MrX takasaki
MrX is fool!

のようなファイル"pptest.txt" をプリプロセッサにかけてみる。-E でプリプロセッサの実行が可能。

gcc -E tttest.txt

処理結果は下記の通り、マクロが展開されている。

# 1 "pptest.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "pptest.c"

takasaki is fool!

次にARM用のgccでコンパイルしQEMUで実行してみる。

ARM版のgcc/QEMUはインストールが必要。

$ arm-linux-gnueabihf-gcc -o hello  hello.c
$ QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf qemu-arm-static hello
Hello!

fileコマンドで生成された内容を確認できる。

$ file hello.o
$ hello.o: ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV), not stripped

次にCソースコードからアセンブリ言語を出力してみる。

$ arm-linux-gnueabihf-gcc -S hello.s  hello.c

結果は下記の通り。

    .arch armv7-a
    .eabi_attribute 28, 1
    .eabi_attribute 20, 1
    .eabi_attribute 21, 1
    .eabi_attribute 23, 3
    .eabi_attribute 24, 1
    .eabi_attribute 25, 1
    .eabi_attribute 26, 2
    .eabi_attribute 30, 6
    .eabi_attribute 34, 1
    .eabi_attribute 18, 4
    .file   "hello.c"
    .text
    .section    .rodata
    .align  2
.LC0:
    .ascii  "Hello!\000"
    .text
    .align  1
    .global main
    .arch armv7-a
    .syntax unified
    .thumb
    .thumb_func
    .fpu vfpv3-d16
    .type   main, %function
main:
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 1, uses_anonymous_args = 0
    push    {r7, lr}
    add r7, sp, #0
    ldr r3, .L3
.LPIC0:
    add r3, pc
    mov r0, r3
    bl  puts(PLT)
    movs    r3, #0
    mov r0, r3
    pop {r7, pc}
.L4:
    .align  2
.L3:
    .word   .LC0-(.LPIC0+4)
    .size   main, .-main
    .ident  "GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0"
    .section    .note.GNU-stack,"",%progbits

.L3,L4などは「ラベル」(「シンボル」とは異なることに注意)

@はコメント

本文書はARMを対象とするが、アーキテクチャが変わってもコンパイラを変えれば同じことが確認できる。

例としてRISC-Vの例を挙げる。

riscv64-linux-gnu-gcc -S hello.c

とすると下記の通り。レジスタ名は異なるがARMと似ていることが分かる。

    .file   "hello.c"
    .option pic
    .text
    .section    .rodata
    .align  3
.LC0:
    .string "Hello!"
    .text
    .align  1
    .globl  main
    .type   main, @function
main:
    addi    sp,sp,-16
    sd  ra,8(sp)
    sd  s0,0(sp)
    addi    s0,sp,16
    lla a0,.LC0
    call    puts@plt
    li  a5,0
    mv  a0,a5
    ld  ra,8(sp)
    ld  s0,0(sp)
    addi    sp,sp,16
    jr  ra
    .size   main, .-main
    .ident  "GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0"
    .section    .note.GNU-stack,"",@progbits

「ディレクティブ」とは   

.string , .text などのこと

https://www.sourceware.org/binutils/docs-2.12/as.info/Pseudo-Ops.html#Pseudo%20Ops

「シンボル」とは

https://linuxcommand.net/nm/

「セクション」とは

http://www.ertl.jp/~takayuki/readings/info/no02.html

「glibc」とは

    .func main
main:
    PUSH {LR}
    LDR R0, =string
    mov R1,#55
    BL  printf
_exit:
    MOV PC, LR
.data
string:
    .asciz "Hello World %d\n"

「ELF(Executable and Linable Format」とは

https://ja.wikipedia.org/wiki/Executable_and_Linkable_Format

ELFファイルの内容はreadelf コマンドで確認することができる。

$ arm-linux-gnueabihf-gcc -c -o hello.o  hello.c
$ arm-linux-gnueabihf-readelf -a  hello.o
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          548 (bytes into file)
  Flags:                             0x5000000, Version5 EABI
  Size of this header:               52 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           40 (bytes)
  Number of section headers:         12
  Section header string table index: 11

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00000000 000034 000018 00  AX  0   0  4
  [ 2] .rel.text         REL             00000000 0001b0 000010 08   I  9   1  4
  [ 3] .data             PROGBITS        00000000 00004c 000000 00  WA  0   0  1
  [ 4] .bss              NOBITS          00000000 00004c 000000 00  WA  0   0  1
  [ 5] .rodata           PROGBITS        00000000 00004c 000007 00   A  0   0  4
  [ 6] .comment          PROGBITS        00000000 000053 00002b 01  MS  0   0  1
  [ 7] .note.GNU-stack   PROGBITS        00000000 00007e 000000 00      0   0  1
  [ 8] .ARM.attributes   ARM_ATTRIBUTES  00000000 00007e 000033 00      0   0  1
  [ 9] .symtab           SYMTAB          00000000 0000b4 0000e0 10     10  12  4
  [10] .strtab           STRTAB          00000000 000194 000019 00      0   0  1
  [11] .shstrtab         STRTAB          00000000 0001c0 000061 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  y (purecode), p (processor specific)

There are no section groups in this file.

There are no program headers in this file.

There is no dynamic section in this file.

Relocation section '.rel.text' at offset 0x1b0 contains 2 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
0000000a  00000d0a R_ARM_THM_CALL    00000000   puts
00000014  00000503 R_ARM_REL32       00000000   .rodata

There are no unwind sections in this file.

Symbol table '.symtab' contains 14 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS hello.c
     2: 00000000     0 SECTION LOCAL  DEFAULT    1
     3: 00000000     0 SECTION LOCAL  DEFAULT    3
     4: 00000000     0 SECTION LOCAL  DEFAULT    4
     5: 00000000     0 SECTION LOCAL  DEFAULT    5
     6: 00000000     0 NOTYPE  LOCAL  DEFAULT    5 $d
     7: 00000000     0 NOTYPE  LOCAL  DEFAULT    1 $t
     8: 00000014     0 NOTYPE  LOCAL  DEFAULT    1 $d
     9: 00000000     0 SECTION LOCAL  DEFAULT    7
    10: 00000000     0 SECTION LOCAL  DEFAULT    6
    11: 00000000     0 SECTION LOCAL  DEFAULT    8
    12: 00000001    24 FUNC    GLOBAL DEFAULT    1 main
    13: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND puts

No version information found in this file.
Attribute Section: aeabi
File Attributes
  Tag_CPU_name: "7-A"
  Tag_CPU_arch: v7
  Tag_CPU_arch_profile: Application
  Tag_ARM_ISA_use: Yes
  Tag_THUMB_ISA_use: Thumb-2
  Tag_FP_arch: VFPv3-D16
  Tag_ABI_PCS_wchar_t: 4
  Tag_ABI_FP_denormal: Needed
  Tag_ABI_FP_exceptions: Needed
  Tag_ABI_FP_number_model: IEEE 754
  Tag_ABI_align_needed: 8-byte
  Tag_ABI_align_preserved: 8-byte, except leaf SP
  Tag_ABI_enum_size: int
  Tag_ABI_VFP_args: VFP registers
  Tag_ABI_optimization_goals: Aggressive Debug
  Tag_CPU_unaligned_access: v6

生成された実行ファイルはobjdumpコマンドで逆アセンブル(disassemble)することができる。

$ arm-linux-gnueabihf-gcc -o hello hello.c
$ arm-linux-gnueabihf-objdump hello
takasaki@D0055817:~/QEMU$ arm-linux-gnueabihf-objdump -d hello

hello:     file format elf32-littlearm


Disassembly of section .init:

000003a0 <_init>:
 3a0:   e92d4008        push    {r3, lr}
 3a4:   eb000026        bl      444 <call_weak_fn>
 3a8:   e8bd8008        pop     {r3, pc}

Disassembly of section .plt:

000003ac <.plt>:
 3ac:   e52de004        push    {lr}            ; (str lr, [sp, #-4]!)
 3b0:   e59fe004        ldr     lr, [pc, #4]    ; 3bc <.plt+0x10>
 3b4:   e08fe00e        add     lr, pc, lr
 3b8:   e5bef008        ldr     pc, [lr, #8]!
 3bc:   00010c08        .word   0x00010c08

000003c0 <__cxa_finalize@plt>:
 3c0:   e28fc600        add     ip, pc, #0, 12
 3c4:   e28cca10        add     ip, ip, #16, 20 ; 0x10000
 3c8:   e5bcfc08        ldr     pc, [ip, #3080]!        ; 0xc08

000003cc <puts@plt>:
 3cc:   e28fc600        add     ip, pc, #0, 12
 3d0:   e28cca10        add     ip, ip, #16, 20 ; 0x10000
 3d4:   e5bcfc00        ldr     pc, [ip, #3072]!        ; 0xc00

000003d8 <__libc_start_main@plt>:
 3d8:   e28fc600        add     ip, pc, #0, 12
 3dc:   e28cca10        add     ip, ip, #16, 20 ; 0x10000
 3e0:   e5bcfbf8        ldr     pc, [ip, #3064]!        ; 0xbf8

000003e4 <__gmon_start__@plt>:
 3e4:   e28fc600        add     ip, pc, #0, 12
 3e8:   e28cca10        add     ip, ip, #16, 20 ; 0x10000
 3ec:   e5bcfbf0        ldr     pc, [ip, #3056]!        ; 0xbf0

000003f0 <abort@plt>:
 3f0:   e28fc600        add     ip, pc, #0, 12
 3f4:   e28cca10        add     ip, ip, #16, 20 ; 0x10000
 3f8:   e5bcfbe8        ldr     pc, [ip, #3048]!        ; 0xbe8

Disassembly of section .text:

000003fc <_start>:
 3fc:   f04f 0b00       mov.w   fp, #0
 400:   f04f 0e00       mov.w   lr, #0
 404:   bc02            pop     {r1}
 406:   466a            mov     r2, sp
 408:   b404            push    {r2}
 40a:   b401            push    {r0}
 40c:   f8df a024       ldr.w   sl, [pc, #36]   ; 434 <_start+0x38>
 410:   a308            add     r3, pc, #32     ; (adr r3, 434 <_start+0x38>)
 412:   449a            add     sl, r3
 414:   f8df c020       ldr.w   ip, [pc, #32]   ; 438 <_start+0x3c>
 418:   f85a c00c       ldr.w   ip, [sl, ip]
 41c:   f84d cd04       str.w   ip, [sp, #-4]!
 420:   4b06            ldr     r3, [pc, #24]   ; (43c <_start+0x40>)
 422:   f85a 3003       ldr.w   r3, [sl, r3]
 426:   4806            ldr     r0, [pc, #24]   ; (440 <_start+0x44>)
 428:   f85a 0000       ldr.w   r0, [sl, r0]
 42c:   f7ff efd4       blx     3d8 <__libc_start_main@plt>
 430:   f7ff efde       blx     3f0 <abort@plt>
 434:   00010b90        .word   0x00010b90
 438:   00000020        .word   0x00000020
 43c:   00000030        .word   0x00000030
 440:   00000034        .word   0x00000034

00000444 <call_weak_fn>:
 444:   e59f3014        ldr     r3, [pc, #20]   ; 460 <call_weak_fn+0x1c>
 448:   e59f2014        ldr     r2, [pc, #20]   ; 464 <call_weak_fn+0x20>
 44c:   e08f3003        add     r3, pc, r3
 450:   e7932002        ldr     r2, [r3, r2]
 454:   e3520000        cmp     r2, #0
 458:   012fff1e        bxeq    lr
 45c:   eaffffe0        b       3e4 <__gmon_start__@plt>
 460:   00010b70        .word   0x00010b70
 464:   0000002c        .word   0x0000002c

00000468 <deregister_tm_clones>:
 468:   4806            ldr     r0, [pc, #24]   ; (484 <deregister_tm_clones+0x1c>)
 46a:   4b07            ldr     r3, [pc, #28]   ; (488 <deregister_tm_clones+0x20>)
 46c:   4478            add     r0, pc
 46e:   4a07            ldr     r2, [pc, #28]   ; (48c <deregister_tm_clones+0x24>)
 470:   447b            add     r3, pc
 472:   4283            cmp     r3, r0
 474:   447a            add     r2, pc
 476:   d003            beq.n   480 <deregister_tm_clones+0x18>
 478:   4b05            ldr     r3, [pc, #20]   ; (490 <deregister_tm_clones+0x28>)
 47a:   58d3            ldr     r3, [r2, r3]
 47c:   b103            cbz     r3, 480 <deregister_tm_clones+0x18>
 47e:   4718            bx      r3
 480:   4770            bx      lr
 482:   bf00            nop
 484:   00010b98        .word   0x00010b98
 488:   00010b94        .word   0x00010b94
 48c:   00010b4c        .word   0x00010b4c
 490:   00000028        .word   0x00000028

00000494 <register_tm_clones>:
 494:   4808            ldr     r0, [pc, #32]   ; (4b8 <register_tm_clones+0x24>)
 496:   4909            ldr     r1, [pc, #36]   ; (4bc <register_tm_clones+0x28>)
 498:   4478            add     r0, pc
 49a:   4a09            ldr     r2, [pc, #36]   ; (4c0 <register_tm_clones+0x2c>)
 49c:   4479            add     r1, pc
 49e:   1a09            subs    r1, r1, r0
 4a0:   447a            add     r2, pc
 4a2:   0fcb            lsrs    r3, r1, #31
 4a4:   eb03 01a1       add.w   r1, r3, r1, asr #2
 4a8:   1049            asrs    r1, r1, #1
 4aa:   d003            beq.n   4b4 <register_tm_clones+0x20>
 4ac:   4b05            ldr     r3, [pc, #20]   ; (4c4 <register_tm_clones+0x30>)
 4ae:   58d3            ldr     r3, [r2, r3]
 4b0:   b103            cbz     r3, 4b4 <register_tm_clones+0x20>
 4b2:   4718            bx      r3
 4b4:   4770            bx      lr
 4b6:   bf00            nop
 4b8:   00010b6c        .word   0x00010b6c
 4bc:   00010b68        .word   0x00010b68
 4c0:   00010b20        .word   0x00010b20
 4c4:   00000038        .word   0x00000038

000004c8 <__do_global_dtors_aux>:
 4c8:   b508            push    {r3, lr}
 4ca:   4b0a            ldr     r3, [pc, #40]   ; (4f4 <__do_global_dtors_aux+0x2c>)
 4cc:   4a0a            ldr     r2, [pc, #40]   ; (4f8 <__do_global_dtors_aux+0x30>)
 4ce:   447b            add     r3, pc
 4d0:   447a            add     r2, pc
 4d2:   781b            ldrb    r3, [r3, #0]
 4d4:   b96b            cbnz    r3, 4f2 <__do_global_dtors_aux+0x2a>
 4d6:   4b09            ldr     r3, [pc, #36]   ; (4fc <__do_global_dtors_aux+0x34>)
 4d8:   58d3            ldr     r3, [r2, r3]
 4da:   b123            cbz     r3, 4e6 <__do_global_dtors_aux+0x1e>
 4dc:   4b08            ldr     r3, [pc, #32]   ; (500 <__do_global_dtors_aux+0x38>)
 4de:   447b            add     r3, pc
 4e0:   6818            ldr     r0, [r3, #0]
 4e2:   f7ff ef6e       blx     3c0 <__cxa_finalize@plt>
 4e6:   f7ff ffbf       bl      468 <deregister_tm_clones>
 4ea:   4b06            ldr     r3, [pc, #24]   ; (504 <__do_global_dtors_aux+0x3c>)
 4ec:   2201            movs    r2, #1
 4ee:   447b            add     r3, pc
 4f0:   701a            strb    r2, [r3, #0]
 4f2:   bd08            pop     {r3, pc}
 4f4:   00010b36        .word   0x00010b36
 4f8:   00010af0        .word   0x00010af0
 4fc:   00000024        .word   0x00000024
 500:   00010b22        .word   0x00010b22
 504:   00010b16        .word   0x00010b16

00000508 <frame_dummy>:
 508:   e7c4            b.n     494 <register_tm_clones>
 50a:   bf00            nop

0000050c <main>:
 50c:   b580            push    {r7, lr}
 50e:   af00            add     r7, sp, #0
 510:   4b03            ldr     r3, [pc, #12]   ; (520 <main+0x14>)
 512:   447b            add     r3, pc
 514:   4618            mov     r0, r3
 516:   f7ff ef5a       blx     3cc <puts@plt>
 51a:   2300            movs    r3, #0
 51c:   4618            mov     r0, r3
 51e:   bd80            pop     {r7, pc}
 520:   0000005e        .word   0x0000005e

00000524 <__libc_csu_init>:
 524:   e92d 43f8       stmdb   sp!, {r3, r4, r5, r6, r7, r8, r9, lr}
 528:   4607            mov     r7, r0
 52a:   4e0c            ldr     r6, [pc, #48]   ; (55c <__libc_csu_init+0x38>)
 52c:   4688            mov     r8, r1
 52e:   4d0c            ldr     r5, [pc, #48]   ; (560 <__libc_csu_init+0x3c>)
 530:   4691            mov     r9, r2
 532:   447e            add     r6, pc
 534:   f7ff ef34       blx     3a0 <_init>
 538:   447d            add     r5, pc
 53a:   1b76            subs    r6, r6, r5
 53c:   10b6            asrs    r6, r6, #2
 53e:   d00a            beq.n   556 <__libc_csu_init+0x32>
 540:   3d04            subs    r5, #4
 542:   2400            movs    r4, #0
 544:   f855 3f04       ldr.w   r3, [r5, #4]!
 548:   3401            adds    r4, #1
 54a:   464a            mov     r2, r9
 54c:   4641            mov     r1, r8
 54e:   4638            mov     r0, r7
 550:   4798            blx     r3
 552:   42a6            cmp     r6, r4
 554:   d1f6            bne.n   544 <__libc_csu_init+0x20>
 556:   e8bd 83f8       ldmia.w sp!, {r3, r4, r5, r6, r7, r8, r9, pc}
 55a:   bf00            nop
 55c:   00010992        .word   0x00010992
 560:   00010988        .word   0x00010988

00000564 <__libc_csu_fini>:
 564:   4770            bx      lr
 566:   bf00            nop

Disassembly of section .fini:

00000568 <_fini>:
 568:   e92d4008        push    {r3, lr}
 56c:   e8bd8008        pop     {r3, pc}

以下から続きを書いていく

gdb-multiarch

関数呼び出し/glib/printf/ABI

https://developer.arm.com/architectures/system-architectures/software-standards/abi

Stack

ストロングリオーダー https://www.aps-web.jp/academy/ca/226/

thumb命令

[参考書籍]

ディジタル回路設計とコンピュータアーキテクチャ [ARM版] https://www.amazon.co.jp/dp/4434218484

ARMアセンブラ入門 https://www.amazon.co.jp/dp/4863541260

ASSEMBLY LANGUAGE https://www.amazon.co.jp/dp/1492135283

Binary Hacks https://www.amazon.co.jp/dp/4873112885

ハロー“Hello-World”-OSと標準ライブラリのシゴトとしくみ https://www.amazon.co.jp/dp/B01GH9AM8C

ARM Assembly Language Programming with Raspberry Pi using GCC https://www.amazon.co.jp/Assembly-Language-Programming-Raspberry-using/dp/197005400X/

⚠️ **GitHub.com Fallback** ⚠️