考虑以下函数:
_atomic_raw_lock:
.global _atomic_raw_lock
.type _atomic_raw_lock, %function
1: ldxr x9, [x0] //atomic load from memory pointed to by x0
cbz x9, 2f //branch if zero (unlocked)
wfe //sleep if locked
b 1b
2: mov x9, #0x01 //set x9 to be LOCKED (1).
stxr w10, x9, [x0]
dsb sy
cbz w10, 3f // atomic store success?
b 1b
3: ret
该函数从c代码中调用,并将地址存储为x0中的64位整数作为其第一个参数。该程序在qemu中按预期运行。通过在调用此函数的这一行之前和之后设置硬件引脚,我已经确定这是问题所在。这个函数永远不会返回。x9和w10是调用者保存的(我假设c调用代码会自动保存它们)。
详细信息:在pi 3 b+上运行,使用aarch64-buildroot-linux-gnu (glibc静态链接)从toolchains.bootlin.com进行交叉链接编译,在调用此函数之前,一切都在真实硬件上运行良好。构建命令:
aarch64-linux-g++ -g -std=gnu++17 -O0 -Wall -fno-exceptions -Wextra -Wno-attributes -fno-asynchronous-unwind-tables -Wno-sign-compare -c start.S -o
aarch64-linux-ld start.o main.o -T link.ld -o kernel8.elf -l:libc.a -l:libstdc++.a -l:libc.so -l:libgcc_s.so
ld文件:
OUTPUT_ARCH(aarch64)
ENTRY(_start)
MEMORY
{
RAM (xrw) : ORIGIN = 0x80000, LENGTH = 0x40000000
}
SECTIONS
{
PROVIDE(__start_prog_mem = .); /*I may want to use this in c somehow*/
.text : /*The place where code goes*/
{
KEEP(*(.text.boot)) /*Keep this even if it is not used*/
*(.text .text.* .gnu.linkonce.t*) /*all variations of text and
the gnu generated (for the c ability) text sections*/
} > RAM /*These sections now belong in .text*/
.bss : /*Uninitialized data goes here, will not load at runtime.*/
{
. = ALIGN(4); /*align the current location to 4 bytes*/
__bss_start = .; /*define __bss_start to be at the current location.*/
*(.bss .bss.* .gnu.linkonce.b.*)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4); /*align the current location to 4 bytes*/
__bss_end = .; /*Define __bss_end to be at the current location.*/
} > RAM
.data : /*Initialized global and static data*/
{
. = ALIGN(4); /*align the current location to 4 bytes*/
__data_begin = .;
*(.data .data.* .gnu.linkonce.d*) /*Put all data sections here.*/
*(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
. = ALIGN(4);
__data_end = .;
} > RAM
.rodata : /*const data*/
{
. = ALIGN(4); /*align the current location to 4 bytes*/
__rodata_begin = .;
*(.rodata .rodata.* .gnu.linkonce.r*) /*All const data sections,
including the gnu leftovers*/
*(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
. = ALIGN(4);
__rodata_end = .;
} > RAM
.stack_core0 :
{
. = ALIGN(16); /*stack must be 16 byte aligned*/
__stack_start_core0 = .;
. = . + 1024; /*el0 size*/
__el0_stack_core0 = .; /*el0 stack*/
. = . + 1048576; /*el1 size*/
__el1_stack_core0 = .; /*el1 stack*/
PROVIDE(__el1_stack_core0 = .);
. = . + 16384; /*el2 stack size*/
__el2_stack_core0 = .;
. = ALIGN(16);
__stack_end_core0 = .;
} > RAM
.stack_core1 :
{
. = ALIGN(16); /*stack must be 16 byte aligned*/
__stack_start_core1 = .;
. = . + 1024; /*el0 size*/
__el0_stack_core1 = .; /*el0 stack*/
. = . + 1048576; /*el1 size*/
__el1_stack_core1 = .; /*el1 stack*/
PROVIDE(__el1_stack_core1 = .);
. = . + 16384; /*el2 stack size*/
__el2_stack_core1 = .;
. = ALIGN(16);
__stack_end_core1 = .;
} > RAM
.stack_core2 :
{
. = ALIGN(16); /*stack must be 16 byte aligned*/
__stack_start_core2 = .;
. = . + 1024; /*el0 size*/
__el0_stack_core2 = .; /*el0 stack*/
. = . + 1048576; /*el1 size*/
__el1_stack_core2 = .; /*el1 stack*/
PROVIDE(__el1_stack_core2 = .);
. = . + 16384; /*el2 stack size*/
__el2_stack_core2 = .;
. = ALIGN(16);
__stack_end_core2 = .;
} > RAM
.stack_core3 :
{
. = ALIGN(16); /*stack must be 16 byte aligned*/
__stack_start_core3 = .;
. = . + 1024; /*el0 size*/
__el0_stack_core3 = .; /*el0 stack*/
. = . + 1048576; /*el1 size*/
__el1_stack_core3 = .; /*el1 stack*/
PROVIDE(__el1_stack_core3 = .);
. = . + 16384; /*el2 stack size*/
__el2_stack_core3 = .;
. = ALIGN(16);
__stack_end_core3 = .;
} > RAM
_end = .; /*Define _end to be at the current location*/
PROVIDE(__end_prog_mem = .); /*I may want to use this in c somehow*/
.heap :
{
. = ALIGN(4);
__heap_start = .;
} > RAM
/DISCARD/ : /*Any sections listed here will not be included*/
{
/* *(.comment*) /*Exclude any comments made by the compiler*/
/* *(.gnu*) /*Exclude any version numbers included by the compiler*/
/* *(.note*) /*Exclude any notes made by the compiler.*/
/* *(.eh_frame*) /*This sections is ecluded because it contains asyncronous
unwind tbles we dont need.*/
}
}
__bss_size = (__bss_end - __bss_start) >> 3; /*Define the symbol to hold the
size of the .bss sections. This size will be in single units of 8 bytes
(due to shift >> 3)*/
__prog_mem_size = (__end_prog_mem - __start_prog_mem);
删除原子锁定机制(最上面的代码列表)允许程序运行,但由于非线程安全代码,输出会变得混乱。即使是一个简单的bool标志也不会工作,因为正常的读-修改-写不是多核安全的。
问题重述:为什么这在模拟器(qemu)上运行,而不是在实际硬件上运行。已确认上述_atomic_raw_lock函数列表在实际硬件上调用时挂起,但在qemu上调用时不挂起。
编辑:代码在QEMU中运行良好,这让我相信它不是死锁。我已经通过运行一个测试来确认这一点,在这个测试中,程序所做的一切都是锁定一次,然后永远旋转。在这些情况下,问题仍然存在。
https://stackoverflow.com/questions/53478330
复制相似问题