5

我们正在尝试将 linux 映像加载到特定位置的 DRAM 中,DRAM 结束地址是 0x80000000,我们从引导日志中了解到“mem 设备结束地址是 0x80000000”。我们正在将映像加载到地址“0x5000000”并且在图像中的 variuos 部分被加载到大于“0x80000000”的某个地址之前,例如从启动日志中再次举例

 loading section to address 0xc5000000 from file position 0x1000, size is 0x5ac13e

上一行中“从文件位置 0x1000”的含义是什么。

加载的第一部分是 .text 部分,下面是我们的部分标题的 vmlinux 图像转储

[Nr]      Name           Type            Addr     Off    Size   ES Flg Lk Inf Al

[ 0]                     NULL            00000000 000000 000000 00      0   0  0

 [ 1]   .text            PROGBITS        c5000000 001000 5ac13e 00  AX  0   0 4096

 [ 2]      .notes           NOTE            c55ac140 5ad140 000168 00  AX  0   0  4

 [ 3]    __ex_table        PROGBITS        c55ac2b0 5ad2b0 000fe0 00   A  0   0  4

 [ 4]   .rodata           PROGBITS        c55ae000 5af000 20a930 00   A  0   0 64

 [ 5]   __bug_table       PROGBITS        c57b8930 7b9930 0075fc 00   A  0   0  1

 [ 6]   .pci_fixup        PROGBITS        c57bff2c 7c0f2c 001a90 00   A  0   0  4

 [ 7]    .builtin_fw       PROGBITS        c57c19bc 7c29bc 0000cc 00   A  0   0  4

它是一个相当大的列表,所以没有发布完整的。但是我们可以在这里看到一件事。文本部分大于 DRAM 结束地址,所以图像不应该被正确加载,尽管在加载它保留的第一部分后我们没有收到任何错误在加载其他部分但在此消息之后它挂起。

    program load complete, entry point: 0x5000000, size: 0x92e7fc

我的问题是如何将这些不同的部分地址与我们的 DRAM 地址对齐,是否可以在这里使用 objcopy 实用程序来更改这些不同部分的地址。

有没有办法在编译之前设置这些段地址?第二件事可能是这个 Hang afer 程序加载完成的原因。

4

3 回答 3

6

from file position 0x1000意思是它所说的。你有它在转储:

[Nr]      Name           Type            Addr     Off    Size   ES Flg Lk Inf Al
...
[ 1]   .text            PROGBITS        c5000000 001000 5ac13e 00  AX  0   0 4096

它是该.text部分在文件中开始的位置,在 offset 处0x1000

但是我们可以在这里看到的一件事 .text 部分大于 DRAM 结束地址

不,它不是更大(至少不是更大的意义上),它的编译期望它将被加载0xc5000000到内存中的地址。

所以图像不应该被正确加载,尽管我们在加载第一部分后没有收到任何错误,它会继续加载其他部分

图像可以在任何地方加载,它只是用于加载目的的数据。

OTOH,如果loading section to address 0xc5000000意思是它所说的那样,由于您的 RAM 以0x7fffffff.

但在此消息之后它挂起。

这是意料之中的。机器代码很少与位置无关,因此如果您将其加载到与应该加载​​的位置不同的位置,它将无法工作。或者如果它甚至没有被加载,那么你要执行什么?垃圾。

有没有办法在编译之前设置这些段地址?

根据系统的不同,您可能拥有以下两个选项之一或两者兼有:

  • 以这样一种方式设置页面转换,即虚拟地址从0xc5000000和向上映射到0x5000000整个程序的物理地址和向上
  • 找到您的编译器正在使用的链接器脚本,并将初始部分地址从 更改0xc50000000x5000000,谷歌搜索,请参阅编译器/链接器文档

此外,入口点位于0x5000000. 并不是说这一定是错误的,只是这种情况很少发生。我会确保start标签(或_start其他任何标签)确实收到与本节开头相同的地址.text。如果由于某种原因不是这种情况,则链接器脚本或编译器/链接器命令行选项或加载程序有问题。

于 2013-03-20T11:27:43.127 回答
3

你用什么装载机?“图像”的形式是什么?U-boot 镜像,raw 一,vmlinux ELF 文件?我猜最后一个是根据节的存在等来判断的。从 ELF 文件中,您应该加载的不是节,而是所谓的程序头。例如,这是 OpenRISC linux 内核程序头文件列表(使用 获得readelf -l):

Elf file type is EXEC (Executable file)
Entry point 0xc0000000
There are 2 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x002000 0xc0000000 0x00000000 0x231728 0x232000 RWE 0x2000
  LOAD           0x234000 0xc0232000 0x00232000 0x17c78c 0x18bfcc RWE 0x2000

 Section to Segment mapping:
  Segment Sections...
   00     .text .rodata __ksymtab __ksymtab_gpl __ksymtab_strings __param __modver 
   01     .data __ex_table .head.text .init.text .init.data .bss 

VirtAddr查看和之间的区别PhysAddrc由于通常的 Linux 内核映射而被删除)。自然地,物理地址应该用于加载。

内核为符号、节等使用虚拟地址的原因是,在引导过程中,您可以快速进入 MMU 初始化的时刻,虚拟地址是唯一有效的地址。

最后,关于更改这些地址。事实上,正如 Alexey 所指出的,链接描述文件是关键。您可以在 中找到这些arch/(your arch)/kernel/vmlinux.lds.S。但关键是这是 IMO 不是你的问题,问题可能在于装载机或其选项。

于 2013-03-26T14:32:54.943 回答
1

检查你的 arch/arm/mach-xxx/Makefile.boot (你使用 arm board 对吗?)

  zreladdr-y        += 0x80008000
params_phys-y       := 0x80000100
initrd_phys-y       := 0x80800000

这是来自 Ti omap3 芯片。

我认为您将需要相同的

于 2013-03-30T15:24:56.997 回答