这个汇编程序如何打印“Hello World”?

时间:2016-07-10 17:58:59

标签: assembly arm

.data
.global _start
_start:
    mov r7, #4
    mov r0, #1
    mov r2, #12
    ldr r4, =#0x6c6c6548
    str r4, [pc, #4]
    mov r1, pc
    add pc, pc, #8
    strbt r6, [ip], -r8, asr #10
    svcvs 0x0057206f
    beq 0x193b248
    swi #0
    mov r7, #1
    mov r0, #0
    swi #0

我偶然发现了这个小型ARM组装程序,它打印出“Hello World”。将其另存为test.s以进行测试:

$ as -o test.o test.s
$ ld -o test test.o
$ ./test
Hello World
$

这是如何工作的?我在整个程序中看不到一个字符串。它也不会从其他任何地方读取字符串;看起来这个代码就是打印字符串所需的全部内容。字符串来自哪里?

1 个答案:

答案 0 :(得分:1)

这是有趣位的注释:

  mov r7, #4
  mov r0, #1
  mov r2, #12
  ldr r4, =#0x6c6c6548
A str r4, [pc, #4]
B mov r1, pc
C add pc, pc, #8
D strbt r6, [ip], -r8, asr #10
E svcvs 0x0057206f
F beq 0x193b248
G swi #0
  mov r7, #1
  mov r0, #0
  swi #0

A处的商店定位地点D - 正如评论中所指出的那样,该字(以小端序排列)创建了4个ASCII字节“地狱” - 存储在顶部那里的无意义指令(机器代码是0xe66c6548 - 关闭,但不够好)。这可能也是数据部分的原因,以确保它是可写的 * 。同时,E处的指令的机器代码是0x6f57206f,这使得“o Wo”。指令F特别棘手,因为该地址必须导致相对分支偏移,一旦编码,看起来像“rld” ** - beq编码是0x0annnnnn,其中nnnnnn是26位二进制补码偏移值的前24位 - 请注意,顶部字节中的条件代码和操作码构成最终换行符。

指令BD的地址放入r1,即指向字符串开头的指针。 r0和r2显然是其他必要的系统调用参数,而r7是系统调用号本身(我懒得查找它,但我假设r0中的1是stdout,r2中的12是字符数,和系统调用4是write)。

最后,说明CG处系统调用的跳转,因此DEF都没有“说明”实际上是执行的(其余的只是在进行exit系统调用)。

非常简洁,适用于特技代码。

*并且可能还依赖于加载器中的一些向后兼容性行为,使数据部分可执行。

**偶然发生在我的binutils 2.26链接器上,可能是由于最近版本中默认的部分对齐已经改变。