I have built a linux kernel image (arm64) and I can do disassembly using this command (goes out to stdout).
aarch64-none-elf-objdump -b binary -D -m aarch64 Image
The output looks like this.
arch/arm64/boot/Image: file format binary
Disassembly of section .data:
0000000000000000 <.data>:
0: 140fc000 b 0x3f0000 <=== see this branch to 3f0000
4: 00000000 udf #0
8: 00080000 .inst 0x00080000 ; undefined
c: 00000000 udf #0
10: 004bb000 .inst 0x004bb000 ; undefined
14: 00000000 udf #0
(skip)
3dbe48: 756e694c .inst 0x756e694c ; undefined
3dbe4c: 00000078 udf #120
...
3f0000: d280067b mov x27, #0x3333 // #51 \
3f0004: 5800157c ldr x28, 0x3f02b0 |
3f0008: 9100239c add x28, x28, #0x8 | added for debug
3f000c: f800879b str x27, [x28], #8 |
3f0010: 5800151a ldr x26, 0x3f02b0 |
3f0014: f900035c str x28, [x26] /
3f0018: 94000008 bl 0x3f0038
3f001c: 97fc47fb bl 0x302008
The FPGA board I’m working on has only 8 MB on-chip ram (0x80000000 ~ 0x80800000) in place of DDR range(0x80000000 ~ ) for now and I loaded the kernel image to 0x80080000 and jumped to 0x80080000. (I’m using u-boot-spl to make this jump). I can’t use debugger for the board yet and I wanted to check if the linux kernel code really runs so added a simple debug code which writes 0x3333 at some memory location. (The 6 lines at 0x3f0000 using x27 and x28 is the code.) Original linux code doesn’t have it and would do bl preserve_boot_args
. (here bl 0x3f0038
).
This is the debug code I added in arch/arm64/kernel/start.S. (6 linex using x27, x28)
ENTRY(stext)
mov x27, #0x3333 \
ldr x28, =myptr |
add x28, x28, #8 |
str x27, [x28], #8 | added for debug
ldr x26, =myptr |
str x28, [x26] /
bl preserve_boot_args
bl el2_setup // Drop to EL1, w0=cpu_boot_mode
.section ".__mydebug", "aw"
myptr: .double 0x807e0000
So if the next value of myptr
is 0x3333, the code should have worked. I modified the linux linker script as below (added a section .mydebug) and made the value myptr
be placed there.
PECOFF_EDATA_PADDING
__pecoff_data_rawsize = ABSOLUTE(. - __initdata_begin);
_edata = .;
.mydebug : { \
. = ALIGN(8); | ==> added section
KEEP(*(.__mydebug)); |
} /
BSS_SECTION(0, 0, 0)
. = ALIGN(PAGE_SIZE);
init_pg_dir = .;
And the System.map file looks like this.
0000000000000000 A __rela_size
0000000000000000 A _kernel_flags_le_hi32
0000000000000000 A _kernel_offset_le_hi32
0000000000000000 A _kernel_size_le_hi32
000000000000000a A _kernel_flags_le_lo32
0000000000000200 A PECOFF_FILE_ALIGNMENT
000000000006b808 A __pecoff_data_rawsize
0000000000080000 A _kernel_offset_le_lo32
0000000000095000 A __pecoff_data_size
00000000004bb000 A _kernel_size_le_lo32
00000000004be948 A __rela_offset
ffffffc010080000 t _head
ffffffc010080000 T _text
ffffffc010080800 T __exception_text_start
ffffffc010080800 T _stext
ffffffc010080800 T do_undefinstr
ffffffc0100809d0 T do_sysinstr
ffffffc010080a40 T do_mem_abort
ffffffc010080ae0 T do_el0_irq_bp_hardening
ffffffc010080b60 T do_el0_ia_bp_hardening
(skip)
ffffffc010511800 D secondary_holding_pen_release
ffffffc010511808 D __mmuoff_data_end
ffffffc010511808 D _edata
ffffffc010511808 D myptr <==== see this
ffffffc010511810 B __bss_start
ffffffc010512000 b bm_pmd
ffffffc010513000 b bm_pte
ffffffc010514000 B empty_zero_page
ffffffc010515000 B reset_devices
ffffffc010515008 b execute_command
ffffffc010515010 b ramdisk_execute_command
I wanted to see the value of myptr
and the next value.(all 64 bit). But the System.map shows all virtual addresses. How can I know the physical address of myptr
? In previous baremetal programas, I could see the memory using the map file (it showed the physical address, virtual=physical), but in this case the System.map shows virtual addresses which I can’t localize.. I tried looking at 0x80080000 + 0x3f0004 + 0x3f02b0 or 0x80080000 + 0x3f02b0 but couldn’t find it. How can I find the location of myptr
??
ADD (Jan 5, 2022) :
I found .mysection is followed by _bss which will be initialized by 0, so I added some space before _bss_start. And I thought the instruction 3f0004: 5800157c ldr x28, 0x3f02b0
is ldr (literal) instruction in armv8 arch ref manual C6.2.133 (by first two bits). So the value 0x3f02b0 is PC relative. The PC value at the instant is 0x3f0008 (already incremented by 4) so 0x3f0008 + 0x3f02b0 = 0x7e02b8. Since the kernel images starts at 0x80080000, this location is 0x80080000 + 0x7e02b8 = 0x808602b8 which goes beyond the 8MB range(0x80000000 ~ 0x80800000). If I placed the kernel at 0x80000000, this value would become 0x807e02b8 (in the RAM range).
But still there were strange values in the address next to the address I think is myptr location. And I found the PAGE_OFFSET is 0xffffff00_00000000 by printing it during compile in the file arch/arm64/include/asm/memory.h.(not 0xffffffc0_00000000 as shown in System.map). I tried looking at (address of myptr according to System.map) - PAGE_OFFSET + (kernel load address = 0x80000000)
but couldn’t find 0x3333 written in address next to myptr. I tried assuming PAGE_OFFSET 0xffffffc010000000 (then myptr becomes 0x80511808) and 0xffffff0000000000 (then myptr becomes 0xc090511808 which is too big).