汇编语言写的hellworld,在安卓手机上运行

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

小程以为,基本上,大多数人都不必学习汇编的。

所以,本文只是介绍一个大概,让装逼成为可能。

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

(一)怎么写一个hello world?

首先是要知道gnu arm的汇编语法的,用任何语言都是这样。

对于asm的语法,如果愿意,你可以通读一遍“gnu arm汇编手册”,如果不愿意也可以在想了解什么指令时再去查看。

对于代码的编写,用你熟悉的编辑器写就好,保存为.s文件。

比如say hello:

.data msg: .asciz "hello, gnu asm\n" len = . - msg .text .global main main: push {r0,r1,r2,lr} ldr r1, =msg 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机子上运行。android上的执行文件的格式是elf,所以要编译成elf格式的文件。

小程的开发环境是macos。

在mac上,需要使用交叉编译工具,才可以编译出在另一个平台(这里是android平台)使用的程序。

小程使用的是NDK(Native Development Kit)里面的工具,它的目录结构是这样的:

以后,就是使用这个xx-gcc来编译了。

但是,直接使用这个xx-gcc来编译时(比如直接xx-gcc -o test test.c)会遇到识别不了头文件(如stdio.h)的情况,因为没有指定头文件的目录,也没有指定链接时使用的库。

那有没有完整的编译环境呢? 有的,它叫编译工具链

创建编译工具链,需要使用NDK里面的make-standalone-toolchain.sh脚本。

最终的编译脚本是这样的:

#!/bin/bash # toolchain TOOLCHAIN=~/asmtoolchain SYSROOT=$TOOLCHAIN/sysroot/ ANDROID_NDK_ROOT=/Users/sky/Documents/android-ndk-r10d NDK_PATH=$ANDROID_NDK_ROOT MIN_PLATFORM=android-8 TOOLCHAIN_VER=arm-linux-androideabi-4.8 OUT_NAME=helloasm OBJS=helloasm.s if [ ! -d $SYSROOT ]; then $NDK_PATH/build/tools/make-standalone-toolchain.sh --platform=$MIN_PLATFORM --install-dir=$TOOLCHAIN --toolchain=$TOOLCHAIN_VER fi PATH=$TOOLCHAIN/bin:$PATH CC=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, %function main: @ 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}

是不是有对应的模样?

总结一下,汇编语言使用于特定的场景,而大多数人并不需要理会它,但文中提到的编译工具链的使用,是有必要理解一下的,因为对于编译特定的第三方库,或者写简单的测试例子,是有帮助的。总之,本文实用性较低。

原文发布于微信公众号 - 广州小程(gh_3e79faa8a715)

原文发表时间:2018-01-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券