Home > Software engineering >  Cannot write to variable defined in LD linker script when compiling with -Os option
Cannot write to variable defined in LD linker script when compiling with -Os option

Time:09-07

I am writing a program to run bare metal. I am trying to write to a variable from a custom linker script. The code runs perfectly when compiled with -O0 options but not as expected when compiled with -Os option.

The code I used is as follows.

main.c:

#define TTB_BASE (&Image$$TTB)
extern unsigned int Image$$TTB;

int main ()
{
    *TTB_BASE = 56326;

    unsigned int *ttb=TTB_BASE 16;

    for (int i = 0; i < 8; i   )
    {
        *ttb   = 1;
    }
    *(volatile unsigned int*)(0x00100000) = *TTB_BASE;
}

When compiled with -Os option, the code *TTB_BASE = 56326; is seems to be optimized out and the value is not stored to the address TTB_BASE.

The linker script used:

ARMCA7.ld

ENTRY(main)
SECTIONS
{
    . = 0x00160000;
    .text : { *(.text*) }
    .data : { *(.data .data.* .gnu.linkonce.d*) }
    .bss (NOLOAD) : {
        . = ALIGN(16);
        *(.bss .bss.*)
        *(COMMON)
    }
    . = 0x00170000;
    .ttb :
    {
        Image$$TTB = .;
    }
}

Compiling statement:

arm-none-eabi-gcc -mcpu=cortex-a7 -Os -std=gnu99 -c -o main.o main.c
arm-none-eabi-gcc -mcpu=cortex-a7 -Os -T ARMCA7.ld -nostartfiles -Xlinker --gc-sections -Wl,-Map,"main.map" -o main.elf main.o

Disassembly got:

Address : Opcode         Statement
-------   ------         ---------
 8                        unsigned int *ttb=TTB_BASE 16;
                      main:
00160000: 24 30 9f e5   ldr     r3, [pc, #36]   ; 0x16002c <main 44>
12                            *ttb   = 1;
00160004: 01 10 a0 e3   mov     r1, #1
00160008: 20 20 83 e2   add     r2, r3, #32
0016000c: 04 10 83 e4   str     r1, [r3], #4
10                        for (int i = 0; i < 8; i   )
00160010: 02 00 53 e1   cmp     r3, r2
00160014: fc ff ff 1a   bne     0x16000c <main 12>
14                        *(volatile unsigned int*)(0x00100000) = *TTB_BASE;
00160018: 60 20 13 e5   ldr     r2, [r3, #-96]  ; 0xffffffa0
0016001c: 01 36 a0 e3   mov     r3, #1048576    ; 0x100000
15                    }
00160020: 00 00 a0 e3   mov     r0, #0
14                        *(volatile unsigned int*)(0x00100000) = *TTB_BASE;
00160024: 00 20 83 e5   str     r2, [r3]
15                    }
00160028: 1e ff 2f e1   bx      lr
0016002c: 40 00 17 00   andseq  r0, r7, r0, asr #32

It can be seen that nothing is written to the address TTB_BASE which is 0x00170000 defined in the linker script, and the value written to address 0x00100000 is wrong.

Is there some bug in the code or linker script?

Note:

If I change the first two lines of main.c to the following code,

#define TTB_BASE (Image$$TTB)
extern unsigned int Image$$TTB[];

The code can be correctly compiled and the address TTB_BASE is written correctly. However, as I seen from other questions, both approach should be correct.

gcc version used:

arm-none-eabi-gcc --version
arm-none-eabi-gcc.exe (Arm GNU Toolchain 11.3.Rel1) 11.3.1 20220712
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

I also test the code with arm-none-eabi-gcc.exe 10.3.1 20210621 (release) and got the same problem.

CodePudding user response:

Your external variable has no side effects visible to the compiler, and as such it is allowed to optimize the assignment out.

The standard compliant way to avoid this is to add the qualifier volatile. It tells the compiler that this variable has side effects. Therefore it cannot optimize the assignment out.

extern volatile unsigned int Image$$TTB;

You need this qualifier also, if you have multiple threads like interrupt service routines, which share variables with each other or the main thread.


Addition:

As others pointed out in comments, there is an error in the linker script. You don't reserve space for the variable.

CodePudding user response:

I found that the question posted is related to external variables other than linker script. Please refer to this new post for further discussion.

  • Related