解惑在Linux系统中XCP标定的虚拟地址和MAP文件的关系
什么是XCP
XCP的全名是通用测量和校正协定(Universal Measurement and Calibration Protocol),是ASAM提出的网络通讯协定,目的是要连接校正系统及电子控制单元(ECU)。此一协定可以在运行时读写微处理器里的变数以及内存。可以用计时器或是运作条件触发事件,同步触发或读取完整的资料集。也可以用XCP烧录快闪存储器。 —- 维基百科
虚拟地址空间
虚拟地址(vitural address)和物理地址(Physical Address) 在现代的操作系统中,为了让其他的程序能方便的运行在操作系统上,需要完成的一个很重要的抽象是「每个程序有自己的地址空间,且地址空间范围是一样的」,这将会减少了上层程序的大量麻烦,否则程序本身要维护自己需要的物理内存,这也会导致极大程度的不安全。个执行上看到的地址空间,就是虚拟内存。而访问虚拟内存的地址就是虚拟地址(Virtual Address),与之对应的是物理地址(Physical Address)。
一个小程序
#include <stdio.h>
int num;
int main(void)
{
printf("num addr:\t\t%p\n",&num);
return 0;
}
执行结果:
$ num addr: 0x55d87ad22034
$ num addr: 0x561a3b94b034
$ num addr: 0x55ded5b71034
由于Linux系统使用的是虚拟地址,可知每次的地址都不一样。
MAP 文件
map文件就是通过编译器编译之后,生成的程序、数据及IO空间信息的一种映射文件,里面包含函数大小,入口地址等一些重要信息。
gcc 生成 MAP 文件 增加参数 ”-Wl,-Map,out.map“ 即可
Linux下根据MAP生成 A2L文件
A2L文件中保存有需要标定的地址,标定地址即根据MAP 文件获取的全局变量地址
豁然开朗的demo
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#define __USE_GNU
#include <link.h>
void *baseAddr;
static int dump_phdr(struct dl_phdr_info *pinfo, size_t size, void *data)
{
// Application modules has no name
if (0 == strlen(pinfo->dlpi_name))
{
extern char __data_start;
baseAddr = (void*)pinfo->dlpi_addr;
}
return 0;
}
int num;
int main(void)
{
dl_iterate_phdr(dump_phdr, NULL);
printf("base addr:\t\t%p\n",baseAddr);
printf("num addr:\t\t%p\n",&num);
printf("num relative addr:\t0x%lx\n", (uint64_t)((void*)&num - baseAddr));
return 0;
}
程序输出:
base addr: 0x55b2f6a5f000
num addr: 0x55b2f6c60018
num relative addr: 0x201018
MAP 文件:
.bss 0x0000000000201010 0x18
*(.dynbss)
.dynbss 0x0000000000201010 0x0 /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o
*(.bss .bss.* .gnu.linkonce.b.*)
.bss 0x0000000000201010 0x0 /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o
.bss 0x0000000000201010 0x0 /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o
.bss 0x0000000000201010 0x1 /usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o
.bss 0x0000000000201011 0x0 /tmp/ccgkH8UK.o
.bss 0x0000000000201011 0x0 /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS)
.bss 0x0000000000201011 0x0 /usr/lib/gcc/x86_64-linux-gnu/7/crtendS.o
.bss 0x0000000000201011 0x0 /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.o
*(COMMON)
*fill* 0x0000000000201011 0x7
COMMON 0x0000000000201018 0x10 /tmp/ccgkH8UK.o
0x0000000000201018 num
0x0000000000201020 baseAddr
0x0000000000201028 . = ALIGN ((. != 0x0)?0x8:0x1)
由以上demo可知 通过 dl_iterate_phdr() 这个函数实现了变量地址的过程,解决虚拟地址带来的标定问题。