使用 MEMORY 时忽略的段地址

Section address ignored when using MEMORY

我有一个 linker 脚本:

SECTIONS
{
  .text 0x42000:
  {
    *(.text*)
  }

  aligned_dot = ALIGN(0x10 * 1024);  

  .data aligned_dot :
  {
    *(.data*)
  }
}

如果我 link 一个(非常简单的)文件使用它它给出了我所期望的:

Sections:
Idx Name          Size      Address          Type
  0               00000000 0000000000000000 
  1 .text         00000008 0000000000042000 TEXT DATA 
  2 .data         00000000 0000000000044000 TEXT BSS

aligned_dot是:

00044000 A aligned_dot

但是,我想使用这样的 MEMORY 命令:

MEMORY
{
  ram (wxa) : ORIGIN = 0x42000, LENGTH = 0x100000
}

SECTIONS
{
  .text :
  {
    *(.text*)
  }

  aligned_dot = ALIGN(0x10 * 1024);  

  .data aligned_dot :
  {
    *(.data*)
  }
}

当我link使用这个脚本时,.data部分的地址似乎被忽略了!

Sections:
Idx Name          Size      Address          Type
  0               00000000 0000000000000000 
  1 .text         00000008 0000000000042000 TEXT DATA 
  2 .data         00000000 0000000000042008 TEXT BSS

尽管 aligned_dot 仍然是:

00044000 A aligned_dot

这很奇怪吧?到底是怎么回事?这是使用 Clang 的 LLD。

我认为这可能是 LLVM 中的错误。在 LinkerScript.cpp 中我们有:

void LinkerScript::assignOffsets(OutputSection *Sec) {
  if (!(Sec->Flags & SHF_ALLOC))
    Dot = 0;
  else if (Sec->AddrExpr)
    setDot(Sec->AddrExpr, Sec->Location, false);

  Ctx->MemRegion = Sec->MemRegion;
  Ctx->LMARegion = Sec->LMARegion;
  if (Ctx->MemRegion)
    Dot = Ctx->MemRegion->CurPos;

在我看来,如果设置了 MemRegion,它会忽略 AddrExpr。如果我将倒数第二行更改为此,则它可以正常工作:

  if (Ctx->MemRegion && !Sec->AddrExpr)

编辑:如果您的手动地址之后还有部分,那么这似乎还不够。你需要这样的东西,虽然我对此更不确定:

void LinkerScript::assignOffsets(OutputSection *Sec) {

  if (!(Sec->Flags & SHF_ALLOC))
    Dot = 0;
  else if (Sec->AddrExpr)
    setDot(Sec->AddrExpr, Sec->Location, false);

  Ctx->MemRegion = Sec->MemRegion;
  Ctx->LMARegion = Sec->LMARegion;
  if (Ctx->MemRegion && !Sec->AddrExpr)
    Dot = Ctx->MemRegion->CurPos;

  switchTo(Sec);

  if (Ctx->MemRegion && Sec->AddrExpr) {
    if (Ctx->MemRegion->CurPos < Dot) {
      expandMemoryRegions(Dot - Ctx->MemRegion->CurPos);
    }
  }