0

I have a program targeting a small memory ARM R5 CPU, being compiled with gcc 11.2.0 and ld 2.37.20210721.

I have a critical symbol that I would like to know the address of, even if the binary was stripped. I would prefer to not waste memory by allocating memory to store the address in RAM or even worse, also allocating a known constant so that you can grub through the program to find where the variable is. Basically have something in a post-strip'd elf file which tells me where the variable is.

Ideally the linker script could say ADDR(symbol), but that apparently is not a thing.

Bonus points if the section starts to look like .comment without an "Addr" reported by readelf and without the W write (or of course X) flag.

I tried to use the attribute section and a linker script to make the section NOLOAD and put the memory somewhere innocuous (e.g. into address space used by some processor registers/code that I cannot use anyway). However, when I did so, the actual value was not preserved according to objdump. If I removed NOLOAD, the value was saved but then of course it was loaded into this no longer innocuous memory.

Example program:

__attribute__((unused)) unsigned int GENERAL_FAULT = 0;
volatile unsigned int critical = 5;
__attribute__((section(".criticaladdr"),unused)) const void *critical_addr = (void *)&critical;

void r5_main(void)
{
  while (1)
  {
    if (critical != 5)
      critical = 5;
  }
}

In this example, the .criticaladdr section is writable and has RAM allocated to it, and objdump -s -j .criticaladdr showed the correct address.

  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00000000 010000 0000c0 00  AX  0   0  4
  [ 2] .note.gnu.bu[...] NOTE            000000c0 0100c0 000024 00   A  0   0  4
  [ 3] .data             PROGBITS        000000e4 0100e4 000004 00  WA  0   0  4
  [ 4] .criticaladdr     PROGBITS        000000e8 0100e8 000004 00  WA  0   0  4
[...]
  [ 9] .comment          PROGBITS        00000000 01011b 000012 01  MS  0   0  1

Adding a linker script to try to prevent the load and move the allocated ram somewhere innocuous kept the memory writable, but more problematically no longer stored the actual data--objdump -s -j .criticaladdr showed 0x0 as the contents.

…
MEMORY
{
…
  OCM_RAM_ATF (r) : ORIGIN = 0xFFFD0000, LENGTH = 0x20000
}
…
SECTIONS
{
…
.criticaladdr (NOLOAD) : { KEEP(*(".criticaladdr")) } > OCM_RAM_ATF
}

1 Answer 1

0

I was able to achieve everything except making the memory marked as read-only, but I guess that probably doesn't really matter for this use case. The READONLY type feature is pretty new, so might also be a feature missing in my ld version.

It required the use of the "backwards comparability" and "rarely used" "INFO" section type.

…
SECTIONS
{
…
.criticaladdr 0 (INFO) : { *(.criticaladdr) }
}

Readelf reports:

  [ 8] .criticaladdr     PROGBITS        00000000 010118 000004 00   W  0   0  4

Objdump objdump -s -j .criticaladdr a.elf reports:

Contents of section .criticaladdr:
 0000 e4000000                             ....            

And 0xe4 is indeed the correct address in my test program.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.