英文:
How to load a variable's address into a register using assembly? (arm64 linux kernel code)
问题
以下是翻译后的代码部分,不包含问题内容:
回到汇编代码一段时间后..
我已经把这段代码放在 Linux 内核启动后 (linux-5.15.68)。
.global mydebug2
....(跳过)
SYM_CODE_START(primary_entry)
mov x27, #0x3333
ldr x28, mydebug2
add x28, x28, #8
str x27, [x28], #8
ldr x26, =myptr
str x28, [x26]
b .
bl preserve_boot_args
bl init_kernel_el // w0=cpu_boot_mode
"mydebug2" 缓冲区在 init/main.c 中定义如下。
#include <test/mwtest.h>
uint64_t mydebug2[MWBUF_LENGTH] = {0,};
uint32_t myidx = 0;
uint64_t mycnt = 0; // 用于左移,64 位
asmlinkage __visible void __init __no_sanitize_address start_kernel(void)
{
char *command_line;
char *after_dashes;
请注意,这只是代码部分的翻译。
英文:
Back to assembly code after a while..
I have put this code right after the linux kernel starts (linux-5.15.68).
.global mydebug2
....(skip)
SYM_CODE_START(primary_entry)
mov x27, #0x3333
ldr x28, mydebug2
add x28, x28, #8
str x27, [x28], #8
ldr x26, =myptr
str x28, [x26]
b .
bl preserve_boot_args
bl init_kernel_el // w0=cpu_boot_mode
The buffer "mydebug2" is defined in init/main.c like this.
#include <test/mwtest.h>
uint64_t mydebug2[MWBUF_LENGTH] = {0,};
uint32_t myidx = 0;
uint64_t mycnt = 0; // for left shift, 64bit
asmlinkage __visible void __init __no_sanitize_address start_kernel(void)
{
char *command_line;
char *after_dashes;
When I compile it, I get this error at the end.
> LD .tmp_vmlinux.kallsyms1 arch/arm64/kernel/head.o: in function
> primary_entry':
mydebug2' defined in .bss section in init/main.o make: ***
> /home/ckim/prj1/LinuxDevDrv/linux-5.15.68/arch/arm64/kernel/head.S:97:(.init.text+0x4):
> relocation truncated to fit: R_AARCH64_LD_PREL_LO19 against symbol
>
> [Makefile:1214: vmlinux] Error 1
I guess mydebug2 is virtual address (like 0xffffffc008c4b028), and ldr x28, mydebug2
instruction cannot load that address into x28. How can I load the address to x28?
(BTW, I know in the current setting, how the physcial address is mapped into kernel virtual address. I see 0xffffffc008000000 corresponds to physcial memory 0x80200000).
ADD : as Nate Eldredge suggested I tried using the adrp and add pair which is defined in arch/arm64/include/asm/assembler.h as below.
/*
* Pseudo-ops for PC-relative adr/ldr/str <reg>, <symbol> where
* <symbol> is within the range +/- 4 GB of the PC.
*/
/*
* @dst: destination register (64 bit wide)
* @sym: name of the symbol
*/
.macro adr_l, dst, sym
adrp \dst, \sym
add \dst, \dst, :lo12:\sym
.endm
.... more (skip) ...
答案1
得分: 1
生成ARM64寄存器中地址的最常见方法是使用adrp
指令,使用pc-relative寻址。 使用ldr x28, =mydebug2
语法来从字面池中加载数据通常也是一种选择,但在这种情况下,内核的重定位修复尚未完成,因此这种方法不可行。
因此,根据 https://stackoverflow.com/questions/64838776/understanding-arm-relocation-example-str-x0-tmp-lo12zbi-paddr/64841097#64841097,您可以执行以下操作:
mov x27, #0x3333
adrp x28, mydebug2
add x28, x28, #:lo12:mydebug2
add x28, x28, #8
str x27, [x28], #8
由于完整的相对地址不能适应一个指令中,adrp
给您21位的高位,而#lo12:mydebug2
给出了12位的低位。
实际上,您可以通过将+8
包含在地址计算中来节省一条指令:
mov x27, #0x3333
adrp x28, mydebug2+8
add x28, x28, #:lo12:mydebug2+8
str x27, [x28], #8
(注意,+8需要同时出现在两个地方,以考虑+8可能导致低12位发生进位,而这是add
指令可以编码为立即数的唯一情况。)
在下一行中,您需要对myptr
执行相同的操作。
英文:
The most common way to generate an address in a register on ARM64 is pc-relative, using adrp
. The ldr x28, =mydebug2
syntax, to load from the literal pool, is usually also an option, but in this case, it seems that the kernel's relocation fixups have not been done yet, so that won't work.
So following https://stackoverflow.com/questions/64838776/understanding-arm-relocation-example-str-x0-tmp-lo12zbi-paddr/64841097#64841097, you want to do
mov x27, #0x3333
adrp x28, mydebug2
add x28, x28, #:lo12:mydebug2
add x28, x28, #8
str x27, [x28], #8
Since the complete relative address won't fit in one instruction, adrp
gives you the 21 high bits, and #lo12:mydebug2
is the 12 low bits.
Actually, you can save one instruction by building the +8
into the address computation:
mov x27, #0x3333
adrp x28, mydebug2+8
add x28, x28, #:lo12:mydebug2+8
str x27, [x28], #8
(Note the +8 needs to be in both places to account for the possibility that the +8 causes a carry out of the low 12 bits, which is all that add
can encode as an immediate.)
You'll need to do the same thing with myptr
on the next line.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论