'Hello World' in ARM64 Assembly

 

cat hello.s
.data

/* Data segment: define our message string and calculate its length. */
msg:
    .ascii        "Hello, ARM64!\n"
len = . - msg

.text

/* Our application's entry point. */
.globl _start
_start:
    /* syscall write(int fd, const void *buf, size_t count) */
    mov     x0, #1      /* fd := STDOUT_FILENO */
    ldr     x1, =msg    /* buf := msg */
    ldr     x2, =len    /* count := len */
    mov     w8, #64     /* write is syscall #64 */
    svc     #0          /* invoke syscall */

    /* syscall exit(int status) */
    mov     x0, #0      /* status := 0 */
    mov     w8, #93     /* exit is syscall #1 */
    svc     #0          /* invoke syscall */

 

 

Error: can't open hello.S for reading: No such file or directory
[root@centos7 ARM-assembly-examples]# as -o hello.o hello.s 
[root@centos7 ARM-assembly-examples]# ld -s -o hello hello.o
[root@centos7 ARM-assembly-examples]# ./hello
Hello, ARM64!

 

 

.data
msg_output: .asciz "proc start \n"
.global _start
.text
_start:
    // 调用printf
    ldr x0, addr_msg_output  // x0 ← &msg_output [64-bit]
    bl printf                // call printf
end:
    mov x0,x2
    mov x8, 93
        svc 0

 

 

[root@centos7 ARM-assembly-examples]# ld -g -o  print print.o -lc -I /lib64/ld-linux-aarch64.so.1
[root@centos7 ARM-assembly-examples]# ./print
proc start 

 

 

 

 

 

 

.data
msg_start: .asciz "proc start \n"
msg_end: .asciz "proc end \n"
.global _start
.text
_start:
    // 调用printf
    ldr x0, addr_msg_start // x0 ← &msg_output [64-bit]
    bl printf                // call printf
end:
    ldr x0, addr_msg_end // x0 ← &msg_output [64-bit]
    bl printf                // call printf
    mov x0,x2
    mov x8, 93
        svc 0
addr_msg_start: .dword msg_start
addr_msg_end: .dword msg_end
~

 

[root@centos7 ARM-assembly-examples]# as -g -o print.o print.s
[root@centos7 ARM-assembly-examples]# ld -g -o  print print.o -lc -I /lib64/ld-linux-aarch64.so.1
[root@centos7 ARM-assembly-examples]# ./print
proc start 
proc end 

 

 堆栈

 

sub   sp, sp, #(8 * 14)       // Allocate space for the whole block.
...
str   x0, [sp, #(8 * 11)]     // Write to slot 11.
...
ldr   x0, [sp, #(8 * 11)]     // Read from slot 11.
...
add   sp, sp, #(8 * 14)       // Free the space at the end of the block.

 

.data
msg_start: .asciz "proc start \n"
msg_end: .asciz "proc end \n"
msg_loop_start: .asciz "loop start\n"
msg_loop_end: .asciz "loop end\n"
msg_even_start: .asciz "even start\n"
msg_odd_start: .asciz "odd start\n"
.global _start
.text
_start:
    sub   sp, sp, #(8 * 14)
       // 调用printf
    ldr x0, addr_msg_start // x0 ← &msg_output [64-bit]
    bl printf                // call printf
    mov x1, #123           /* r1 ← 123 */
    mov x2, #0             /* r2 ← 0 */
loop:
    str   x1, [sp, #(8 * 11)]
    str   x2, [sp, #(8 * 7)]
    ldr x0, addr_msg_loop_start// x0 ← &msg_output [64-bit]
    bl printf                // call printf
    ldr   x1, [sp, #(8 * 11)]
    ldr   x2, [sp, #(8 * 7)]
    cmp x1, #1             /* compare r1 and 1 */
    beq end                /* branch to end if r1 == 1 */
 
    and x3, x1, #1         /* r3 ← r1 & 1 */
    cmp x3, #0             /* compare r3 and 0 */
    bne odd                /* branch to odd if r3 != 0 */
even:
    str   x1, [sp, #(8 * 11)]
    str   x2, [sp, #(8 * 7)]
    ldr x0, addr_msg_even_start// x0 ← &msg_output [64-bit]
    bl printf                // call printf
    ldr   x1, [sp, #(8 * 11)]
    ldr   x2, [sp, #(8 * 7)]
    mov x1, x1, ASR #1     /* r1 ← (r1 >> 1) */
    b end_loop
odd:
    str   x1, [sp, #(8 * 11)]
    str   x2, [sp, #(8 * 7)]
    ldr x0, addr_msg_odd_start// x0 ← &msg_output [64-bit]
    bl printf                // call printf
    ldr   x1, [sp, #(8 * 11)]
    ldr   x2, [sp, #(8 * 7)]
    add x1, x1, x1, LSL #1 /* r1 ← r1 + (r1 << 1) */
    add x1, x1, #1         /* r1 ← r1 + 1 */
 
end_loop:
    str   x1, [sp, #(8 * 11)]
    str   x2, [sp, #(8 * 7)]
    ldr x0, addr_msg_loop_end// x0 ← &msg_output [64-bit]
    bl printf                // call printf
    ldr   x1, [sp, #(8 * 11)]
    ldr   x2, [sp, #(8 * 7)]
    add x2, x2, #1         /* r2 ← r2 + 1 */
    b loop                 /* branch to loop */
end:
    mov x0,x2
    mov x8, 93
    svc 0
addr_msg_start: .dword msg_start
addr_msg_end: .dword msg_end
addr_msg_loop_start: .dword msg_loop_start
addr_msg_loop_end: .dword msg_loop_end
addr_msg_odd_start: .dword msg_odd_start
addr_msg_even_start: .dword msg_even_start

 

[root@centos7 ARM-assembly-examples]# as -g -o collatz64.o collatz64.s
[root@centos7 ARM-assembly-examples]# ld -o collatz64 collatz64.o -lc -I /lib64/ld-linux-aarch64.so.1
[root@centos7 ARM-assembly-examples]# ./collatz64 

branch

[root@centos7 ARM-assembly-examples]# cat branch.s
.data
msg_start: .asciz "proc start \n"
msg_end: .asciz "proc end \n"
msg_loop_start: .asciz "loop start\n"
msg_loop_end: .asciz "loop end\n"
msg_even_start: .asciz "even start\n"
msg_odd_start: .asciz "odd start\n"
.global _start
.text
_start:
    sub   sp, sp, #(8 * 14)
       // 调用printf
    ldr x0, addr_msg_start // x0 ← &msg_output [64-bit]
    bl printf                // call printf
    mov x1, #124           /* r1 ← 123 */
    mov x2, #0             /* r2 ← 0 */
loop:
    str   x1, [sp, #(8 * 11)]
    str   x2, [sp, #(8 * 7)]
    ldr x0, addr_msg_loop_start// x0 ← &msg_output [64-bit]
    bl printf                // call printf
    ldr   x1, [sp, #(8 * 11)]
    ldr   x2, [sp, #(8 * 7)]
    cmp x1, #1             /* compare r1 and 1 */
    beq end                /* branch to end if r1 == 1 */
 
    and x3, x1, #1         /* r3 ← r1 & 1 */
    cmp x3, #0             /* compare r3 and 0 */
    bne odd                /* branch to odd if r3 != 0 */
even:
    ldr x0, addr_msg_even_start// x0 ← &msg_output [64-bit]
    bl printf                // call printf
    //b end
odd:
    ldr x0, addr_msg_odd_start// x0 ← &msg_output [64-bit]
    bl printf                // call printf
    b end 
end:
    mov x0,x2
    mov x8, 93
    svc 0
addr_msg_start: .dword msg_start
addr_msg_end: .dword msg_end
addr_msg_loop_start: .dword msg_loop_start
addr_msg_loop_end: .dword msg_loop_end
addr_msg_odd_start: .dword msg_odd_start
addr_msg_even_start: .dword msg_even_start

 

 

[root@centos7 ARM-assembly-examples]# as -g -o branch.o branch.s
[root@centos7 ARM-assembly-examples]# ld -o branch branch.o -lc -I /lib64/ld-linux-aarch64.so.1
[root@centos7 ARM-assembly-examples]# ./branch
proc start 
loop start
even start
odd start

 

 

 

.data
 
msg_input: .asciz "Please type a number: "
scanf_fmt : .asciz "%d"
msg_output: .asciz "Fibonacci number %d is %ld\n"
 
.text
.global _start
_start:
    stp x19, x30, [sp, #-16]! // Keep x19 and x30 (link register)
    sub sp, sp, #16           // Grow the stack because for a local
                              // variable used by scanf.
    /*
      堆栈如下:
      Contents  Address
      | var |    [sp]       We will use the first 4 bytes for scanf
      |     |    [sp, #8]
      | x19 |    [sp, #16]
      | x30 |    [sp, #24]
     */
 
    // 调用printf
    ldr x0, addr_msg_input   // x0 ← &msg_input  [64-bit]
    bl printf                // call printf
 
    // 调用call
    //   scanf("%d", &var);
    mov x1, sp               // x1 ← sp
    ldr x0, addr_scanf_fmt   // x0 ← &scanf_fmt  [64-bit]
    bl scanf                 // call scanf
 
    // 调用fibonacci
    //   res = fibonacci(var);
    ldr w0, [sp]             // w0 ← *sp   [32-bit]
    bl fibonacci             // call fibonacci
 
    // Setup call to printf
    //   printf("Fibonacci number %d is %ld\n", var, res);
    mov x2, x0               // x2 ← x0
                           
    ldr w1, [sp]             // w1 ← *sp   [32-bit]
    ldr x0, addr_msg_output  // x0 ← &msg_output [64-bit]
    bl printf                // call printf
 
    add sp, sp, #16          // Shrink the stack.
    ldp x19, x30, [sp], #16  // Restore x19 and x30 (link register)
    mov w0, #0               // w0 ← 0
    mov x8, 93
    svc 0


fibonacci:
    // fibonacci(n) -> result
    //   n 是 32位 通过w0传递
    //   结果是 64位 ,通过 x0传递
    stp x19, x30, [sp, #-16]!  // Keep x19 and x30 (link register)
    stp x20, x21, [sp, #-16]!  // Keep x20 and x21
    /*
      堆栈如下:
      | x20 |    [sp]
      | x21 |    [sp, #8]
      | x19 |    [sp, #16]
      | x30 |    [sp, #24]
     */
 
    cmp w0, #1                // Compare w0 with 1 and update the flags
    ble simple_case           // if w0 <= 1 branch to simple_case
                              // (otherwise continue to recursive_case)
 
    recursive_case:           // recursive case
                              // (this label is not used, added for clarity)
      mov w19, w0             // w19 ← w0
      // Set up call to fibonacci
      //     fibonacci(n-1);
      sub w0, w0, #1          // w0 ← w0 - 1
      bl fibonacci            // call fibonacci
      mov x20, x0             // x20 ← x0
 
      sub w0, w19, #2         // w0 ← w19 - 2
      bl fibonacci            // call fibonacci
      mov x21, x0             // x21 ← x0
 
      add x0, x20, x21        // x0 ← x20 + x21
      b end                   // (unconditional) branch to end
 
    simple_case:
      sxtw x0, w0             // x0 ← ExtendSigned32To64(w0)
 
    end:
      ldp x20, x21, [sp], #16  // Restore x20 and x21
      ldp x19, x30, [sp], #16  // Restore x19 and x30 (link register)
    ret

addr_msg_input: .dword msg_input
addr_msg_output: .dword msg_output
addr_scanf_fmt: .dword scanf_fmt

 

 

 

[root@centos7 ARM-assembly-examples]# as -g -o fibo.o fibo.s
[root@centos7 ARM-assembly-examples]# ld -g -o fibo fibo.o -lc -I /lib64/ld-linux-aarch64.so.1
[root@centos7 ARM-assembly-examples]# ./fibo 
Please type a number: 4
Fibonacci number 4 is 3

 

Calling assembly functions from C  ARM64

Introduction to ARM64 architecture (Chapter 3 experiment)

[root@centos7 ARM-assembly-examples]# gcc -o main  main.c compare.s --static -g
[root@centos7 ARM-assembly-examples]# ./main
big data: 6
[root@centos7 ARM-assembly-examples]# cat main.c 
#include <stdio.h>
extern int compare_data(int a, int b);
int main()
{ 
int val;
val = compare_data(5, 6);
printf("big data: %d\n", val);
}
[root@centos7 ARM-assembly-examples]# cat compare.s 
.section .text
.globl compare_data
compare_data:
        cmp x0, x1
        csel x0, x0, x1, hi // Conditional selection instruction
        ret
[root@centos7 ARM-assembly-examples]# 

 

assembly functions call c

[root@centos7 ARM-assembly-examples]# gcc -c main.s
[root@centos7 ARM-assembly-examples]# gcc -c compare.c
[root@centos7 ARM-assembly-examples]# gcc -o main main.o compare.o
[root@centos7 ARM-assembly-examples]# ./main
big data: 6
[root@centos7 ARM-assembly-examples]# 

 

 

[root@centos7 ARM-assembly-examples]# cat main.s 
.section .data
.align 3
print_data:
.string "big data: %d\n"
.section .text
.globl main
main:
stp x29, x30, [sp, -16]!
mov x0, #6
mov x1, #5
bl compare_data
mov x1, x0
ldr x0, =print_data
bl printf
ldp x29, x30, [sp], 16
ret
[root@centos7 ARM-assembly-examples]# cat compare.c
int compare_data(int a, int b)
{ 
return (a >= b) ? a : b;
}
[root@centos7 ARM-assembly-examples]# 

 

 相对寻址ldr

[root@centos7 ARM-assembly-examples]# cat lds.s 
.text

.globl main
main :
  ldr X0, address_of_global_var64 // X0 ← &global_var64
  ldr X1, [X0]                    // X1 ← *X0
  add X1, X1, #1                  // X1 ← X1 + 1
  str X1, [X0]                    // *X0 ← X1

  ldr X0, address_of_global_var32 // X0 ← &global_var32
  ldr W1, [X0]                    // W1 ← *X0
  add W1, W1, #1                  // W1 ← W1 + 1
  str W1, [X0]                    // *X0 ← W1

  mov W0, #0                      // W0 ← 0
  ret                             // exit program
address_of_global_var64 : .dword global_var64
address_of_global_var32 : .dword global_var32

 

 

[root@centos7 ARM-assembly-examples]# as -o lds.o lds.s
[root@centos7 ARM-assembly-examples]# ld -s -o lds lds.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400078
lds.o: In function `address_of_global_var64':
(.text+0x28): undefined reference to `global_var64'
lds.o: In function `address_of_global_var32':
(.text+0x30): undefined reference to `global_var32'

参考Exploring AArch64 assembler – Chapter 5

添加globalvar.s 

// globalvar.s
.data

.balign 8 // Align to 8 bytes
.byte 1
global_var64 : .dword 0x1234  // a 64-bit value of 0x1234
// alternatively: .word 0x1234, 0x0

.balign 4 // Align to 4 bytes
.byte 1
global_var32 : .word 0x5678   // a 32-bit value of 0

 

[root@centos7 ARM-assembly-examples]# as -o lds.o lds.s globalvar.s 
[root@centos7 ARM-assembly-examples]# ld -s -o lds lds.o
ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0
[root@centos7 ARM-assembly-examples]# ./lds
Segmentation fault
[root@centos7 ARM-assembly-examples]# 

反汇编

[root@centos7 ARM-assembly-examples]# objdump -s -d lds > lds.txt
[root@centos7 ARM-assembly-examples]# cat lds.txt 

lds:     file format elf64-littleaarch64

Contents of section .text:
 4000b0 40010058 010040f9 21040091 010000f9  @..X..@.!.......
 4000c0 00010058 010040b9 21040011 010000b9  ...X..@.!.......
 4000d0 00008052 c0035fd6 e9004100 00000000  ...R.._...A.....
 4000e0 f5004100 00000000                    ..A.....        
Contents of section .data:
 4100e8 01341200 00000000 00000000 01785600  .4...........xV.
 4100f8 00                                   .               

Disassembly of section .text:

00000000004000b0 <.text>:
  4000b0:       58000140        ldr     x0, 0x4000d8
  4000b4:       f9400001        ldr     x1, [x0]
  4000b8:       91000421        add     x1, x1, #0x1
  4000bc:       f9000001        str     x1, [x0]
  4000c0:       58000100        ldr     x0, 0x4000e0
  4000c4:       b9400001        ldr     w1, [x0]
  4000c8:       11000421        add     w1, w1, #0x1
  4000cc:       b9000001        str     w1, [x0]
  4000d0:       52800000        mov     w0, #0x0                        // #0
  4000d4:       d65f03c0        ret
  4000d8:       004100e9        .inst   0x004100e9 ; undefined
  4000dc:       00000000        .inst   0x00000000 ; undefined
  4000e0:       004100f5        .inst   0x004100f5 ; undefined
  4000e4:       00000000        .inst   0x00000000 ; undefined
[root@centos7 ARM-assembly-examples]# 
4000b0 +28 =0x4000d8
[root@centos7 ARM-assembly-examples]# objdump -s -d lds.o > lds.o.txt
[root@centos7 ARM-assembly-examples]# cat lds.o.txt 

lds.o:     file format elf64-littleaarch64

Contents of section .text:
 0000 40010058 010040f9 21040091 010000f9  @..X..@.!.......
 0010 00010058 010040b9 21040011 010000b9  ...X..@.!.......
 0020 00008052 c0035fd6 00000000 00000000  ...R.._.........
 0030 00000000 00000000                    ........        
Contents of section .data:
 0000 01341200 00000000 00000000 01785600  .4...........xV.
 0010 00                                   .               

Disassembly of section .text:

0000000000000000 <main>:
   0:   58000140        ldr     x0, 28 <address_of_global_var64>
   4:   f9400001        ldr     x1, [x0]
   8:   91000421        add     x1, x1, #0x1
   c:   f9000001        str     x1, [x0]
  10:   58000100        ldr     x0, 30 <address_of_global_var32>
  14:   b9400001        ldr     w1, [x0]
  18:   11000421        add     w1, w1, #0x1
  1c:   b9000001        str     w1, [x0]
  20:   52800000        mov     w0, #0x0                        // #0
  24:   d65f03c0        ret

0000000000000028 <address_of_global_var64>:
        ...

0000000000000030 <address_of_global_var32>:

测试2

[root@centos7 ARM-assembly-examples]# cat  hello3.s
.global _start
.text
_start:
    mov x17, #0
    lewp:
    mov x0, #1
    ldr x1, =msg
    ldr x2, =len
    mov w8, #64
    svc #0
    mov x18, #1
    add x17, x17, x18
    mov x18, #10
    cmp x18, x17
    bgt lewp


    mov x0, #0
    mov w8, #93
    svc #0
.data
    msg: .asciz "Hello World\n"
    len = .-msg

 

 

[root@centos7 ARM-assembly-examples]# as -o hello.o hello3.s
[root@centos7 ARM-assembly-examples]# ld -o hello hello.o
[root@centos7 ARM-assembly-examples]# ./hello 
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World

 

 

 

[root@centos7 ARM-assembly-examples]# objdump -s -d hello.o > hello.o.txt
[root@centos7 ARM-assembly-examples]# cat hello.o.txt 

hello.o:     file format elf64-littleaarch64

Contents of section .text:
 0000 110080d2 200080d2 81010058 a2010058  .... ......X...X
 0010 08088052 010000d4 320080d2 3102128b  ...R....2...1...
 0020 520180d2 5f0211eb ecfeff54 000080d2  R..._......T....
 0030 a80b8052 010000d4 00000000 00000000  ...R............
 0040 0d000000 00000000                    ........        
Contents of section .data:
 0000 48656c6c 6f20576f 726c640a 00        Hello World..   

Disassembly of section .text:

0000000000000000 <_start>:
   0:   d2800011        mov     x17, #0x0                       // #0

0000000000000004 <lewp>:
   4:   d2800020        mov     x0, #0x1                        // #1
   8:   58000181        ldr     x1, 38 <lewp+0x34>
   c:   580001a2        ldr     x2, 40 <lewp+0x3c>
  10:   52800808        mov     w8, #0x40                       // #64
  14:   d4000001        svc     #0x0
  18:   d2800032        mov     x18, #0x1                       // #1
  1c:   8b120231        add     x17, x17, x18
  20:   d2800152        mov     x18, #0xa                       // #10
  24:   eb11025f        cmp     x18, x17
  28:   54fffeec        b.gt    4 <lewp>
  2c:   d2800000        mov     x0, #0x0                        // #0
  30:   52800ba8        mov     w8, #0x5d                       // #93
  34:   d4000001        svc     #0x0
        ...
  40:   0000000d        .word   0x0000000d
  44:   00000000        .word   0x00000000
lewp+0x34=
0x0004 +0x34=0x38





交叉编译 ASM skeleton

Small assembler skeleton, ready to use with following properties:

  • use raw Linux syscalls (man 2 syscall for ABI)
  • no C runtime (crt)
  • gnu assembler gas
 
// file: greet.S

#include <asm/unistd.h>      // syscall NRs

    .arch armv8-a

    .section .text, "ax", @progbits
    .balign 4                // align code on 4byte boundary
    .global _start
_start:
    mov x0, 2                // fd
    ldr x1, =greeting        // buf
    ldr x2, =greeting_len    // &len
    ldr x2, [x2]             // len
    mov w8, __NR_write       // write(2) syscall
    svc 0

    mov x0, 0                // exit code
    mov w8, __NR_exit        // exit(2) syscall
    svc 0

    .balign 8                // align data on 8byte boundary
    .section .rodata, "a", @progbits
greeting:
    .asciz "Hi ASM-World!\n"
greeting_len:
    .int .-greeting

man gcc: file.S assembler code that must be preprocessed.

To cross-compile and run:

 
> aarch64-linux-gnu-g++ -o greet greet.S -nostartfiles -nostdlib          \
    -Wl,--dynamic-linker=/usr/aarch64-linux-gnu/lib/ld-linux-aarch64.so.1 \
  && qemu-aarch64 ./greet
Hi ASM-World!

Cross-compiling on Ubuntu 20.04 (x86_64), paths might differ on other distributions. Explicitly specifying the dynamic linker should not be required when compiling natively on arm64.

 

汇编指令-位置无关码(BL)与绝对位置码(LDR)

 

 比如一个指针(addr)

LDR r0,[addr]相当于r0 = *addr    //指针的内容

b    addr   相当于pc=addr(指针)而不是 pc=*addr   

 

 

位置无关码

即该段代码无论放在内存的哪个地址,都能正确运行。究其原因,是因为代码里没有使用绝对地址,都是相对地址。 

位置相关码(和连接脚本相关)

即它的地址与代码处于的位置相关,是绝对地址

BL :带链接分支跳转指令,也是位置无关码(相对位置),用于调用函数用的。

B:分支跳转指令,指目标不能太远,一般用于同一个文件下的目标地址跳转。

LDR:通常都是作加载指令的,但是它也可以作伪指令,通常有两种不同的表示: 

1)LDR pc, =MyHandleIRQ 表示将MyHandleIRQ地址放入pc寄存器中,相当于PC=MyHandleIRQ 。

例如:

1. LDR r0,=label    //用于加载立即数或一个地址值到指定寄存器中

              //如果label是立即数: LDR r0,=0X123 ;将0X123存入r0中

              //如果name是个标识符: LDR r0,=label_1 ;将label_1所指向的地址值存入r0中

2)LDR PC,MyHandleIRQ 表示将 MyHandleIRQ地址中的值放入pc寄存器中,类似于C语言中的指针形式,相当于PC=*(MyHandleIRQ )。

例如:

  • LDR r0,[r1]        //将R1中的值存到r0中
  • LDR r1,[r2,#16]     //将(r2+16)地址中的内容存到r1中
  • LDR r1,[r2],#4      //将r2地址中的内容存到r1中,同时r2=r2+4

实例:

 1 Reset:                  
 2     ldr sp, =4096           @ 设置栈指针,以下都是C函数,调用前需要设好栈
 3     bl  disable_watch_dog   @ 关闭WATCHDOG,否则CPU会不断重启
 4     // bl是位置无关码,相当于:PCnew = PC + 偏移
 5     //                         PCnew = (4+8) + 0x28 = 0x34
 6     
 7     //ldr pc, =disable_watch_dog  /* 这样写将出错 */
 8     
 9     bl  clock_init          @ 设置MPLL,改变FCLK、HCLK、PCLK
10     bl  memsetup            @ 设置存储控制器以使用SDRAM
11     bl  copy_steppingstone_to_sdram     @ 复制代码到SDRAM中
12     ldr pc, =on_sdram                   @ 跳到SDRAM中继续执行
13 on_sdram:
14     ldr sp, =0x34000000     @ 设置栈指针
15     ldr lr, =halt_loop      @ 设置返回地址
16     ldr pc, =main           @ 调用main函数
17 halt_loop:
18     b   halt_loop

链接脚本如下,链接地址在0X30000000:

1 SECTIONS {
2     . = 0x30000000;
3     .text          :   { *(.text) }
4     .rodata ALIGN(4) : {*(.rodata)} 
5     .data ALIGN(4) : { *(.data) }
6     .bss ALIGN(4)  : { *(.bss)  *(COMMON) }
7 }

 

反汇编如下:

 1 30000000 <_start>:
 2 30000000:    e3a0da01     mov    sp, #4096    ; 0x1000
 3 30000004:    eb00000a     bl    30000034 <disable_watch_dog>
 4 30000008:    eb00000d     bl    30000044 <clock_init>
 5 3000000c:    eb000026     bl    300000ac <memsetup>
 6 30000010:    eb000040     bl    30000118 <copy_steppingstone_to_sdram>
 7 30000014:    e59ff00c     ldr    pc, [pc, #12]    ; 30000028 <.text+0x28>
 8 
 9 30000018 <on_sdram>:
10 30000018:    e3a0d30d     mov    sp, #872415232    ; 0x34000000
11 3000001c:    e59fe008     ldr    lr, [pc, #8]    ; 3000002c <.text+0x2c>
12 30000020:    e59ff008     ldr    pc, [pc, #8]    ; 30000030 <.text+0x30>
13 
14 30000024 <halt_loop>:
15 30000024:    eafffffe     b    30000024 <halt_loop>
16 30000028:    30000018     andcc    r0, r0, r8, lsl r0
17 3000002c:    30000024     andcc    r0, r0, r4, lsr #32
18 30000030:    30000200     andcc    r0, r0, r0, lsl #4
19 
20 30000034 <disable_watch_dog>:   ...  ...

 

反汇编中可以看出当执行ldr pc, =on_sdram 时的反汇编是 ldr pc, [pc, #12] ; 相当于pc=*(pc+12)=30000018,此时的*(pc+12)是指的pc+12地址所指的地址,所以无论pc怎么变都是指的30000018这个常量来执行on_sdram,属于绝对转移

 

 执行  bl  disable_watch_dog  时,地址0X30000004跳转到0X30000034.这里的0X30000034是通过机器码算出来的,机器码格式如下图所示:

其中[31:28]位是条件码;[27:24]位为“1010”(0xeaffffff)时,表示B跳转指令,为“1011”时,表示BL跳转指令;[23:0]表示偏移地址。

从反汇编中可以看到 bl  disable_watch_dog  的机器码是eb00000a ,二进制为1110 1011 000000000000000000001010

其中1110表示无条件执行,接下的1011就是BL指令,如L==0则就表示B指令,剩下的Offset就是链接位。

BL指令的跳转地址计算:

1.如上图所示,先将24位Offset补码左移两位,得到000000000000000000001010 00 =0X28

2.由于ARM流水线,当前PC永远等于PC+8,所以PC=PC+0X28+8=0X30000004+0X28+8=0X30000034。

若这里的PC值为其它值,算出来的转移地址也会随之改变,所以BL指令为地址无关码,跳转地址与位置无关。

 注:ARM9是3级流水线,也就是PC处理时正在执行第1条指令的同时对第2条指令进行译码,并将第3条指令从存储器中取出,如下图所示,PC总是指向第3条指令取值的地方。

 

 

 

总结

1. 位置无关码:CPU取指时用相对地址取指令(比如pc +4),只要其相对地址没有变,都能够取指并运行。即该段代码无论放在内存的哪个地址,都能正确运行。究其原因,是因为代码里没有使用绝对地址,都是相对地址。

2. 位置相关码:利用绝对地址取指并运行,这就需要你存放程序(链接过程中)需要按照连接脚本的要求那样执行(Makefile里面有 -Ttext xxx指定或连接脚本)。即它的地址与代码处于的位置相关,是绝对地址,如:mov PC ,#0xff;ldr pc,=0xffff等。

 


 Calling assembly functions from C  ARM64

第18部分- Linux ARM汇编 函数调用示例

第20部分- Linux ARM汇编 函数调用斐波那契数列实现

CONDITIONAL EXECUTION

Apress/modern-arm-assembly-language-programming

INTRODUCTION TO WRITING ARM SHELLCODE

'Hello World' in ARM64 Assembly

 

从0学ARM-什么是位置无关码?

https://en.wikipedia.org/wiki/ARM_architecture#ARMv8
https://smist08.wordpress.com/2021/01/08/apple-m1-assembly-language-hello-world/
https://github.com/below/HelloSilicon
https://thinkingeek.com/2013/01/09/arm-assembler-raspberry-pi-chapter-1/
https://peterdn.com/post/2020/08/22/hello-world-in-arm64-assembly/

posted on 2021-11-08 11:25  tycoon3  阅读(702)  评论(0)    收藏  举报

导航