3

I want to compile a program with gcc with link time optimization for an ARM processor. When I compile without LTO, the system gets compiled. When I enable LTO (with -flto), I get the following assembler-error:

Error: invalid literal constant: pool needs to be closer

Looking around the web I found out that this has something to do with the constants in my system, which are placed in a special section called .rodata, which is called a constant pool and is placed right after the .text section in my system. It seems that when compiling with LTO because of inlining and other optimizations this .rodata section gets too far away from the instructions, so that the addressing of the constants is not possible anymore. Is it possible to place the constants right after the function that uses them? Or is it possible to use another addressing mode so the .rodata section can still be addressed? Thanks.

user3035952
  • 301
  • 5
  • 12
  • The constants do not have to be in `.rodata`. Usually, they are placed directly after a function. If you know where this is occurring (we need more context), I maybe able to give better help. For instance, if you have no inline assembler, then use `__attribute__((noinline))` on a specific problematic function. If it is in inline assembler, then other techniques can handle it. `-flto` is fairly new. It is possible for the compiler to locate branches (such as `b 1f` and place the literals). However, in the current form it probably only places them at the end of functions. – artless noise Apr 11 '14 at 16:37
  • For instance, I believe that with `-flto`, your function becomes larger than 4k and the end of the function is not within the `ldr rX,[pc, #immed_12]` range. For resource constrained systems, this can also be bad as the inlining will increase stack use. Also, please give more information on the ARM target if possible (Thumb2?). – artless noise Apr 11 '14 at 16:42
  • Some other possibilities, `-finline-limit=2048`, `--param max-inline-insns-auto=200`, `--param max-inline-insns-single=200`, etc. Basically, tell `-flto` to limit the size of functions. – artless noise Apr 11 '14 at 20:40
  • In my case the constants are placed in .rodata. After compiling without LTO and looking at the disassembly I can see that my constants are placed in .rodata and not at the end of my functions. Unfortunately I don't know which function is casuing a problem, because when compiling I only get the this message: – user3035952 Apr 15 '14 at 08:38
  • ccS21cBJ.s:3152: Error: invalid literal constant: pool needs to be closer – user3035952 Apr 15 '14 at 08:45
  • And of course this file is deleted instantly, so I can't look at it ... is there a way to tell gcc not to delete those tmp files? – user3035952 Apr 15 '14 at 08:46
  • My target is a Cortex-A9 and memory is really not a concern in my system, neither program memory, nor data memory. It is really all about performance. Actually the main reason why I want to use LTO is that I really want to inline as much as possible. – user3035952 Apr 15 '14 at 08:48
  • Smaller/less memory often means faster. It depends on CPU vs memory speed. Anyways, I think you can use `-save-temps`, to keep intermediate files. Which `gcc` and `gold` (binutils) are you using? If you can not tell what function gives the error, how do you know that the constants are in `.rodata`? I have `mplayer` compiled with `-lto` and the constants are **not** in `.rodata`, that would cause this message; but there are *strings*, etc in `.rodata`. The *literal* constants are different; they are not like strings, etc. – artless noise Apr 15 '14 at 14:31
  • Search for `ldr rX, [pc, #constant]`. With `objdump`, an address is also printed in a comment. Like `foobar+0x1223/0xabcd`, the absolute `objdump` address is inside `.text` and just after the function. `objdump` will not know about static functions and often *lto* eliminates external linkage; but the function is there (see `push` and `pop`). – artless noise Apr 15 '14 at 14:46

2 Answers2

1

This is an assembler message, not a linker message, so this happens before sections are generated.

The assembler has a pseudo instruction for loading constants into registers:

    ldr r0, =0x12345678

this is expanded into

    ldr r0, [constant_12345678, r15]
    ...
    bx lr
constant_12345678:
    dw 0x12345678

The constant pool usually follows the return instruction. With function inlining, the function can get long enough that the return instruction is too far away; unfortunately, the compiler has no idea of the distance between memory addresses, and the assembler has no idea of control flow other than "flow does not pass beyond the return instruction, so it is safe to emit the constant pool here".

Unfortunately, there is no good solution at the moment.

You could try an asm block containing

    b 1f
    .ltorg
1:

This will force-emit the constant pool at this point, at the cost of an extra branch instruction.

It may be possible to instruct the assembler to omit the branch if the constant pool is empty, but I cannot test that at the moment, so this is probably not valid:

    .if (2f - 1f)
    .b 2f
    .endif
1:
    .ltorg
2:
Simon Richter
  • 28,572
  • 1
  • 42
  • 64
0

"This is an assembler message, not a linker message, so this happens before sections are generated" - I am not sure but I think it is a little bit more complicated with LTO. Compiling (including assembling) of the individual c-files with LTO enabled works fine and does not cause any problems. The problem occurs when I try to link them together with LTO enabled. I don't know how LTO is exactly done, but apparently this also includes calling the assembler again and then I get this error message. When linking without LTO, everything is fine and when I look at the disassemly I can see that my constants are not placed after a function. Instead all constants are placed in the .rodata section. With LTO enabled because of inlining, my functions probably get to large to reach the constant pool...

user3035952
  • 301
  • 5
  • 12