概述
在学习ARM汇编的时候,我们往往需要将汇编生成为可执行程序以及调试运行。这里使用Android手机作为运行环境。
前置准备:
高版本NDK使用clang套件已经不在提供GUN GCC/GDB
编译
在学习Thumb/ARM32指令时clang
传入tartget armv7a-linux-androideabi${API}
如果只需只要生成thumb代码给clang
传入 -mthumb
参数。
为方便学习这里给出一个示例脚本方便大家学习
#!/bin/zsh
# https://clang.llvm.org/docs/ClangCommandLineReference.html
#指定NDK目录
export NDK_PATH="/Users/fanjack/Library/Android/sdk/ndk/25.2.9519653"
export API=21
# 需要Thumb/ARM32请使用armv7
#export TARGET="armv7a-linux-androideabi${API}"
# 学习ARM64
export TARGET="aarch64-linux-android21"
# export ccOps="-S"
export COMPILER="$NDK_PATH/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang"
export CC="$COMPILER -target ${TARGET} "
# 仅生成 thumb指令
#$CC -mthumb hello.c -o hello.out
# 生成汇编文件
#$CC -S hello.c -o hello.S
# 汇编生成可执行文件
#$CC hello.S -o hello.out
在学习的时候想直接编写汇编文件,然后不知道语法的时候可以按照以下技巧学习。
#include <stdio.h>
int main(int argc,char ** args){
printf("hello world %d\r\n",argc);
return 0;
}
// 如果想学习thumb指令添加-mthumb
$CC -S hello.c -o hello.S
生成的文件如下:
.text
.syntax unified
.eabi_attribute 67, "2.09" @ Tag_conformance
.eabi_attribute 6, 10 @ Tag_CPU_arch
.eabi_attribute 7, 65 @ Tag_CPU_arch_profile
.eabi_attribute 8, 1 @ Tag_ARM_ISA_use
.eabi_attribute 9, 2 @ Tag_THUMB_ISA_use
.fpu neon
.eabi_attribute 34, 1 @ Tag_CPU_unaligned_access
.eabi_attribute 15, 1 @ Tag_ABI_PCS_RW_data
.eabi_attribute 16, 1 @ Tag_ABI_PCS_RO_data
.eabi_attribute 17, 2 @ Tag_ABI_PCS_GOT_use
.eabi_attribute 20, 1 @ Tag_ABI_FP_denormal
.eabi_attribute 21, 0 @ Tag_ABI_FP_exceptions
.eabi_attribute 23, 3 @ Tag_ABI_FP_number_model
.eabi_attribute 24, 1 @ Tag_ABI_align_needed
.eabi_attribute 25, 1 @ Tag_ABI_align_preserved
.eabi_attribute 38, 1 @ Tag_ABI_FP_16bit_format
.eabi_attribute 18, 4 @ Tag_ABI_PCS_wchar_t
.eabi_attribute 26, 2 @ Tag_ABI_enum_size
.eabi_attribute 14, 0 @ Tag_ABI_PCS_R9_use
.file "hello.c"
.globl main @ -- Begin function main
.p2align 2
.type main,%function
.code 16 @ @main
.thumb_func
main:
.fnstart
@ %bb.0:
.save {r7, lr}
push {r7, lr}
.setfp r7, sp
mov r7, sp
.pad #16
sub r1, #16
movs r2, #0
str r2, [sp] @ 4-byte Spill
str r2, [sp, #12]
str r0, [sp, #8]
str r1, [sp, #4]
ldr r1, [sp, #8]
ldr r0, .LCPI0_0
.LPC0_0:
add r0, pc
bl printf
@ kill: def $r1 killed $r0
ldr r0, [sp] @ 4-byte Reload
add sp, #16
pop {r7, pc}
.p2align 2
@ %bb.1:
.LCPI0_0:
.long .L.str-(.LPC0_0+4)
.Lfunc_end0:
.size main, .Lfunc_end0-main
.cantunwind
.fnend
@ -- End function
.type .L.str,%object @ @.str
.section .rodata.str1.1,"aMS",%progbits,1
.L.str:
.asciz "hello world %d\r\n"
.size .L.str, 17
.ident "Android (9352603, based on r450784d1) clang version 14.0.7 (https://android.googlesource.com/toolchain/llvm-project 4c603efb0cca074e9238af8b4106c30add4418f6)"
.section ".note.GNU-stack","",%progbits
你可以修改上面的代码编写相关兴趣汇编语句。(.code 16
指示代码是16位的,.p2align 2
表示对齐大小。在学习的时候需要注意你学习的指令集,其他direction
你可以执行查阅文档)
在你修改汇编文件将其编译成可执行文件
CC hello.S -o hello.out
接着push到手机运行即可
#!bin/zsh
adb push hello.out /data/local/tmp
adb shell "/data/local/tmp/hello.out"
如果在Mac下学习可能需要调用binutils工具可通过homebrew安装.
以下是一些常用命令
#输出二进制节信息
readElf -S hello.out
输出结果:
There are 27 section headers, starting at offset 0xfe0:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 00000000000002a8 000002a8
0000000000000015 0000000000000000 A 0 0 1
[ 2] .note.androi[...] NOTE 00000000000002c0 000002c0
0000000000000098 0000000000000000 A 0 0 4
[ 3] .dynsym DYNSYM 0000000000000358 00000358
0000000000000060 0000000000000018 A 8 1 8
[ 4] .gnu.version VERSYM 00000000000003b8 000003b8
0000000000000008 0000000000000002 A 3 0 2
[ 5] .gnu.version_r VERNEED 00000000000003c0 000003c0
0000000000000020 0000000000000000 A 8 1 4
[ 6] .gnu.hash GNU_HASH 00000000000003e0 000003e0
000000000000001c 0000000000000000 A 3 0 8
[ 7] .hash HASH 00000000000003fc 000003fc
0000000000000028 0000000000000004 A 3 0 4
[ 8] .dynstr STRTAB 0000000000000424 00000424
0000000000000037 0000000000000000 A 0 0 1
[ 9] .rela.dyn RELA 0000000000000460 00000460
0000000000000060 0000000000000018 A 3 0 8
[10] .rela.plt RELA 00000000000004c0 000004c0
0000000000000048 0000000000000018 AI 3 21 8
[11] .rodata PROGBITS 0000000000000508 00000508
0000000000000011 0000000000000001 AMS 0 0 1
[12] .eh_frame_hdr PROGBITS 000000000000051c 0000051c
000000000000002c 0000000000000000 A 0 0 4
[13] .eh_frame PROGBITS 0000000000000548 00000548
000000000000008c 0000000000000000 A 0 0 8
[14] .text PROGBITS 00000000000015d4 000005d4
00000000000000c8 0000000000000000 AX 0 0 4
[15] .plt PROGBITS 00000000000016a0 000006a0
0000000000000050 0000000000000000 AX 0 0 16
[16] .preinit_array PREINIT_ARRAY 00000000000026f0 000006f0
0000000000000010 0000000000000000 WA 0 0 8
[17] .init_array INIT_ARRAY 0000000000002700 00000700
0000000000000010 0000000000000000 WA 0 0 8
[18] .fini_array FINI_ARRAY 0000000000002710 00000710
0000000000000010 0000000000000000 WA 0 0 8
[19] .dynamic DYNAMIC 0000000000002720 00000720
00000000000001d0 0000000000000010 WA 8 0 8
[20] .got PROGBITS 00000000000028f0 000008f0
0000000000000020 0000000000000000 WA 0 0 8
[21] .got.plt PROGBITS 0000000000002910 00000910
0000000000000030 0000000000000000 WA 0 0 8
[22] .bss NOBITS 0000000000003940 00000940
0000000000000008 0000000000000000 WA 0 0 8
[23] .comment PROGBITS 0000000000000000 00000940
00000000000000b2 0000000000000001 MS 0 0 1
[24] .symtab SYMTAB 0000000000000000 000009f8
00000000000003a8 0000000000000018 26 31 8
[25] .shstrtab STRTAB 0000000000000000 00000da0
00000000000000fe 0000000000000000 0 0 1
[26] .strtab STRTAB 0000000000000000 00000e9e
000000000000013f 0000000000000000 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),
D (mbind), p (processor specific)
# 输出反汇编
objdump -d hello.out
hello.out: file format elf64-littleaarch64
Disassembly of section .text:
00000000000015d4 <_start>:
15d4: d503249f bti j
15d8: d280001d mov x29, #0x0 // #0
15dc: d280001e mov x30, #0x0 // #0
15e0: 910003e0 mov x0, sp
15e4: 14000001 b 15e8 <_start_main>
00000000000015e8 <_start_main>:
15e8: d503233f paciasp
15ec: d100c3ff sub sp, sp, #0x30
15f0: a9027bfd stp x29, x30, [sp, #32]
15f4: 910083fd add x29, sp, #0x20
15f8: b0000008 adrp x8, 2000 <printf@plt+0x920>
15fc: b0000009 adrp x9, 2000 <printf@plt+0x920>
1600: b000000a adrp x10, 2000 <printf@plt+0x920>
1604: b0000002 adrp x2, 2000 <printf@plt+0x920>
1608: 910023e3 add x3, sp, #0x8
160c: aa1f03e1 mov x1, xzr
1610: f9447908 ldr x8, [x8, #2288]
1614: f9447d29 ldr x9, [x9, #2296]
1618: f944814a ldr x10, [x10, #2304]
161c: a900a7e8 stp x8, x9, [sp, #8]
1620: f9000fea str x10, [sp, #24]
1624: f9448442 ldr x2, [x2, #2312]
1628: 94000026 bl 16c0 <__libc_init@plt>
000000000000162c <__atexit_handler_wrapper>:
162c: d503245f bti c
1630: b4000060 cbz x0, 163c <__atexit_handler_wrapper+0x10>
1634: aa0003f0 mov x16, x0
1638: d61f0200 br x16
163c: d65f03c0 ret
0000000000001640 <atexit>:
1640: d503245f bti c
1644: aa0003e1 mov x1, x0
1648: 90000000 adrp x0, 1000 <__FRAME_END__+0xab8>
164c: d0000002 adrp x2, 3000 <_DYNAMIC+0x8e0>
1650: 9118b000 add x0, x0, #0x62c
1654: 91250042 add x2, x2, #0x940
1658: 1400001e b 16d0 <__cxa_atexit@plt>
000000000000165c <main>:
165c: d100c3ff sub sp, sp, #0x30
1660: a9027bfd stp x29, x30, [sp, #32]
1664: 910083fd add x29, sp, #0x20
1668: 2a1f03e8 mov w8, wzr
166c: b9000fe8 str w8, [sp, #12]
1670: b81fc3bf stur wzr, [x29, #-4]
1674: b81f83a0 stur w0, [x29, #-8]
1678: f9000be1 str x1, [sp, #16]
167c: b85f83a1 ldur w1, [x29, #-8]
1680: f0ffffe0 adrp x0, 0 <note_android_ident-0x2c0>
1684: 91142000 add x0, x0, #0x508
1688: 94000016 bl 16e0 <printf@plt>
168c: b9400fe0 ldr w0, [sp, #12]
1690: a9427bfd ldp x29, x30, [sp, #32]
1694: 9100c3ff add sp, sp, #0x30
1698: d65f03c0 ret
Disassembly of section .plt:
00000000000016a0 <__libc_init@plt-0x20>:
16a0: a9bf7bf0 stp x16, x30, [sp, #-16]!
16a4: b0000010 adrp x16, 2000 <printf@plt+0x920>
16a8: f9449211 ldr x17, [x16, #2336]
16ac: 91248210 add x16, x16, #0x920
16b0: d61f0220 br x17
16b4: d503201f nop
16b8: d503201f nop
16bc: d503201f nop
00000000000016c0 <__libc_init@plt>:
16c0: b0000010 adrp x16, 2000 <printf@plt+0x920>
16c4: f9449611 ldr x17, [x16, #2344]
16c8: 9124a210 add x16, x16, #0x928
16cc: d61f0220 br x17
00000000000016d0 <__cxa_atexit@plt>:
16d0: b0000010 adrp x16, 2000 <printf@plt+0x920>
16d4: f9449a11 ldr x17, [x16, #2352]
16d8: 9124c210 add x16, x16, #0x930
16dc: d61f0220 br x17
00000000000016e0 <printf@plt>:
16e0: b0000010 adrp x16, 2000 <printf@plt+0x920>
16e4: f9449e11 ldr x17, [x16, #2360]
16e8: 9124e210 add x16, x16, #0x938
16ec: d61f0220 br x17
调试
由于NDK已经放弃GDB的套件改用LLDB,所以本文将使用远程调试方式。
由于参考链接链接写的过于详细,这里不在说明。
LLDB-remote
How do I use lldb to debug C++ code on Android on command line