アセンブリ言語入門 - tuppy5/programing GitHub Wiki
-
「アセンブリ言語(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/
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
「シンボル」とは
「セクション」とは
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/