arm汇编如何编译 | 为什么学古董语言?

来源:互联网 发布:广西安全知识网络竞赛 编辑:程序博客网 时间:2024/06/10 16:42

本文主要讲解如何写一个gnu arm汇编程序,并且编译,使其在安卓手机上运行起来。

图片来自网络

(一)为什么学arm汇编?

如果允许在使用时才去学的话,任何东西都不必提前学习。而“用时才学”的情况是经常存在的,也是有道理的,你的时间跟精力不应该放在一些现在用不上的知识与技能上(以后可能用上?那以后出现再说,先解决已经出现的或即将出现的问题;如果没有问题,那就开心玩耍去吧)。同样,学习arm汇编,最好是因为你“在做”的事情需要用到这些知识与技能,比如要翻译一段别人的汇编代码,比如需要做一些逆向的修改汇编代码的工作,比如需要看懂程序崩溃时的汇编代码,等等。而至于装逼,也是一个理由(装逼也可能让你有一定的大局观)。

(二)怎么写一个hello world?

用你熟悉的编辑器写就好,保存为.s文件。至于gnu arm asm的语法,查一下手册与例子吧。

比如say hello:

  .data    msg:  .asciz  "hello, gnu asm\n"    len = . - msg  .text    .global main                                                                                                                         main:    push    {r0,r1,r2,lr}  ldr     r1, =msg         @ address    mov     r0, #1          @ stdout    ldr     r2, =len         @ length    mov     %r7, $4     /* write is syscall #4 */  swi     $0          /* invoke syscall */  pop     {r0,r1,r2,pc}

再比如求和:

    .data    msg: .asciz "sum=%d\n"    .text     sum:    push {lr}    mov r2, r0    mov r3, r1    add r0, r2, r3    pop {pc}    .global main    main:    push {r0, r1, r2, lr}    mov r0, #100    mov r1, #120    bl sum     mov r1, r0    ldr r0, =msg    bl printf    pop {r0, r1, r2, pc}

(三)怎么编译一个汇编程序?

这里的目标是在android手机上运行。

交叉编译arm汇编源文件

最终要在android机子上运行,那执行文件的格式就是elf,所以要编译成elf格式的文件。

在mac上,要使用交叉编译工具(即编译出另一个平台用的程序的工具),这个工具可以是:arm-linux-androideabi-gcc(目录比如:toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/),但在编译时(比如直接gcc -o test test.c)会遇到识别不了头文件(如stdio.h)的情况,原因是没有指定头文件的目录。

解决办法:使用编译工具链

编译工具链,就是适用于某个场景(比如生成给某个平台用的执行文件)的编译(或链接等)环境,包括了编译时需要使用到的头文件等。

创建这个编译环境,需要使用ndk里面的make-standalone-toolchain.sh脚本。

最终的编译脚本如下:


#!/bin/bash# toolchainTOOLCHAIN=~/asmtoolchainSYSROOT=$TOOLCHAIN/sysroot/ANDROID_NDK_ROOT=/Users/sky/Documents/android-ndk-r10dNDK_PATH=$ANDROID_NDK_ROOTMIN_PLATFORM=android-8TOOLCHAIN_VER=arm-linux-androideabi-4.8OUT_NAME=helloasmOBJS=helloasm.sif [ ! -d $SYSROOT ]; then$NDK_PATH/build/tools/make-standalone-toolchain.sh --platform=$MIN_PLATFORM --install-dir=$TOOLCHAIN --toolchain=$TOOLCHAIN_VERfiPATH=$TOOLCHAIN/bin:$PATHCC=arm-linux-androideabi-gcc#LD=arm-linux-androideabi-ld#AR=arm-linux-androideabi-ar$CC --sysroot=$SYSROOT -o $OUT_NAME $OBJS

以上编译出的执行文件,是elf格式(file helloasm可查看)。

(四)运行执行文件

拷贝执行文件(比如helloasm)到android手机的/data目录下可以运行(先adb push到/sdcard/,再adb shell到手机并拷贝到/data,再chmod 777 helloasm,之后就可以运行)。

(五)反汇编最终的执行文件

把编译出来的执行文件,再反汇编一下,看看跟源文件有多大的差别。

比如把上面求和的执行程序,用hopper反汇编后,可以看到这样的代码(部分):

sum:    @ args = 0, pretend = 0, frame = 8    @ frame_needed = 1, uses_anonymous_args = 0    @ link register save eliminated.    str fp, [sp, #-4]!    add fp, sp, #0    sub sp, sp, #12    mov r3, #10    str r3, [fp, #-8]    mov r3, #3    str r3, [fp, #-12]    ldr r2, [fp, #-8]    ldr r3, [fp, #-12]    add r3, r2, r3    mov r0, r3    sub sp, fp, #0    @ sp needed    ldr fp, [sp], #4    bx  lr    .size   sum, .-sum    .section    .rodata    .align  2.LC0:    .ascii  "%d\012\000"    .text    .align  2    .global main    .type   main, %functionmain:    @ args = 0, pretend = 0, frame = 16    @ frame_needed = 1, uses_anonymous_args = 0    stmfd   sp!, {fp, lr}    add fp, sp, #4    sub sp, sp, #16    str r0, [fp, #-16]    str r1, [fp, #-20]    bl  sum(PLT)    str r0, [fp, #-8]    ldr r3, .L5.LPIC0:    add r3, pc, r3    mov r0, r3    ldr r1, [fp, #-8]    bl  printf(PLT)    mov r3, #0    mov r0, r3    sub sp, fp, #4    @ sp needed    ldmfd   sp!, {fp, pc}

是不是有对应的模样?


写几个小程序,只是熟悉一下asm的一些基础概念(看起来就像在玩),而对于实战,还是要靠信息收集与分析。

欢迎关注我们