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
第20部分- Linux ARM汇编 函数调用斐波那契数列实现
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/