最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

gcc - Define a fixed-position section within a Linker Script of position-independent executable - Stack Overflow

programmeradmin1浏览0评论

I am trying to build a static position-independent executable with gcc provided option -static-pie. The target is bare-metal risc-v, so no OS, no dynamic loader. I have a linker script similar to following:

ENTRY(_start)
SECTIONS {
  .text (READONLY) : ALIGN(64) {
    startup.o(.text.startup)
    *(EXCLUDE_FILE(startup.o) .text .text.*)
  }
  .rodata (READONLY) : ALIGN(64) {
    *(.srodata .srodata.*)
    *(.rodata .rodata.*)
    *(.got .got.plt)
  }
  .data ALIGN(64): {
    __global_pointer$ = . + 0x800;
    *(.sdata .sdata.*)
    *(.data .data.*)
  }
  .bss (NOLOAD): ALIGN(64) {
    _bss_start = .;
    *(.sbss .sbss.*)
    *(.bss .bss.*)
    _bss_end = .;
  }
  .stack (NOLOAD): ALIGN(64) {
    _stack_start = .;
    . = . + 0x400;
    _stack_end = .;
  }
}

and when compiling with -fpie and linking with -static-pie it seems to produce a correct PIE binary which seems to function correctly from any address it is loaded to.

Now, to the problem. Consider we have a special memory region at fixed address which I want the program to use (for example some shared memory with another processor) and I want to define it via the linker script. With position dependent code I would do something like this:

In the code:

    __attribute__((section(".special_section")))
    volatile uint8_t shared_mem[100];

In the linker script:

SECTIONS {
.....
    .special_section 0x12340000 (NOLOAD): {
        *(.special_section)
    }
.....
}

and this will ensure that the array shared_mem is located at the fixed address 0x12340000.

However this does not work with static-pie. The accesses to shared_mem which are generated by the compiler are relative to the address the binary is loaded to (that's the idea of PIE, right?). The question is - is there a way to define a specific output section to have an absolute address?

UPDATE: Here is more info of what I am seeing. With the linker script as above and the extra section as follows:

  .special_section 0x1234AB00 (NOLOAD): {
    *(.special_section)
  }

the following code (except the startup code, which I omit):

#include <stdint.h>

__attribute__((section(".special_section")))
volatile uint8_t shared_mem[100];

int main(void) {
    shared_mem[0] = 0x55;
    while (1);
    return 0;
}

the generated (interleaved) assembly looks like this:

__attribute__((section(".special_section")))
volatile uint8_t shared_mem[100];

    int main(void) {
        shared_mem[0] = 0x55;
      34:   05500793            li  a5,85
      38:   1234b717            auipc   a4,0x1234b
      3c:   acf70423            sb  a5,-1336(a4) # 1234ab00 <shared_mem>
        while (1);
      40:   a001                    j   40 <main+0xc>

As we can see the destination address in a4 is formed using PC-relative instruction auipc, which adds the current PC = 0x38 value with (0x1234b << 12) = 0x1234_B000, and then a4=0x55 is stored at that address at offset -1336 = -0x538 (that is 0x38 + 0x1234B000 - 0x538 = 0x1234B000 = 0x1234AB00 - as expected).

However, if the program is loaded to an address other than 0x0, the PC in the above calculation will be different, so the destination address of the operation will be different too.

发布评论

评论列表(0)

  1. 暂无评论