在内核的include/linux/linkage.h中定义了:
#ifndef ENTRY
#define ENTRY(name) \
.globl name; \
ALIGN; \
name:
#endif
#endif /* LINKER_SCRIPT */
在arch/arm/mach-socfpga/headsmp.S 中定义了一下两个全局变量:
.arch armv7-a
ENTRY(secondary_trampoline)
movw r2, #:lower16:cpu1start_addr
movt r2, #:upper16:cpu1start_addr
/* The socfpga VT cannot handle a 0xC0000000 page offset when loading
the cpu1start_addr, we bit clear it. Tested on HW and VT. */
bic r2, r2, #0x40000000
ldr r0, [r2]
ldr r1, [r0]
bx r1
ENTRY(secondary_trampoline_end)
并在对应的头文件arch/arm/mach-socfpga/core.h中声明:
extern char secondary_trampoline, secondary_trampoline_end;
而在platsmp.c中如何应用这个全局变量呢?
static int __cpuinit socfpga_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
int trampoline_size = &secondary_trampoline_end - &secondary_trampoline; //这里获取这个两个变量的地址,并且根据地址得到这段代码的长度
if (cpu1start_addr) {
memcpy(phys_to_virt(0), &secondary_trampoline, trampoline_size); //拷贝从secondary_trampoline标号开始的代码段地址
__raw_writel(virt_to_phys(socfpga_secondary_startup),
(sys_manager_base_addr+(cpu1start_addr & 0x000000ff)));
flush_cache_all();
smp_wmb();
outer_clean_range(0, trampoline_size);
/* This will release CPU #1 out of reset.*/
__raw_writel(0, rst_manager_base_addr + 0x10);
}
return 0;
}
而标号(变量)secondary_trampoline_end和secondary_trampoline的内容时对应的text的代码段:
root@socfpga_cyclone5:~# memtool -32 0x0045df80 6
Reading 0x6 count starting at address 0x0045DF80
0x0045DF80: E30E2F38 E3482067 E3C22101 E5920000
0x0045DF90: E5901000 E12FFF11
备注:内核空间的地址在2GB处,即0x80000000,而DDR的物理地址在0x0地址处,所以可以从System.map中得到这两个变量的虚拟地址:
8045df80 T secondary_trampoline
8045df98 T secondary_trampoline_end
转成物理地址0x8045df80 - 0x80000000=0x0045df80,并可以用objdump工具反汇编vmlinux,可以查看此虚拟地址处的汇编代码,和上面显示的是一致的。
结论:
汇编中用.global name定义的全局变量在C语言中引用的一段text代码,而该变量的地址也就是这段text代码的地址。
即汇编全局name在C语言中也是以普通C语言全局变量一样使用,要获取这个变量的地址需要用&name获取。
而汇编中:
ldr rx, name 则是读取name标号处的内容。和C语言中直接使用name变量是一致的。(注意这里是name是相对寻址)
在汇编中要想获取name处的地址,则要使用伪指令adr或ldr。
比如:
取短程地址用:
adr rx, label_name
取长程地址用:
ldr rx, = label_name