C语言引用汇编代码里的全局标号或变量

来源:互联网 发布:单片机的加密模式 编辑:程序博客网 时间:2024/04/30 11:19

在内核的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

 

 

原创粉丝点击