zoukankan      html  css  js  c++  java
  • '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/

  • 相关阅读:
    js实现复制功能 javascript
    《架构整洁之道》之组件聚合
    《架构整洁之道》之组件
    js实现导出word
    js实现导出pdf
    《架构整洁之道》之依赖反转原则
    《架构整洁之道》之接口隔离原则
    《架构整洁之道》之里氏替换原则
    解决js地址栏中传递中文乱码的问题
    Windows安装nginx服务
  • 原文地址:https://www.cnblogs.com/dream397/p/15523421.html
Copyright © 2011-2022 走看看