We are using ThreadX and ThreadX Modules in our product, have been doing so for many years. So far we have always built under ARMCC. We now need to build the ThreadX Modules under GCC (12.2 release 1).
We have followed the form of your example (i.e. compilation switches -fpie -fno-plt -mno-pic-data-is-text-relative -msingle-pic-base, no particular linker switches) and in general the code runs, however there is a specific case where these compilation flags do NOT work: when taking the address of a global variable. For instance:
char buffer[100];
char* pBuffer = buffer;
int appModMain()
{
printf("buffer address: %p, buffer address via pBuffer: %p \n", buffer, pBuffer);
}
...results in a printed output of the form:
buffer address: 60C8C25C, buffer address via pBuffer: 1000025C
In other words pBuffer is not being offset correctly. This is clear when you look at the disassembled code:
00000188 <appModMain>:
188: b580 push {r7, lr}
18a: af00 add r7, sp, #0
18c: 4b1a ldr r3, [pc, #104] ; (1f8 <appModMain+0x70>)
18e: f859 3003 ldr.w r3, [r9, r3]
192: 681b ldr r3, [r3, #0]
194: 461a mov r2, r3
196: 4b19 ldr r3, [pc, #100] ; (1fc <appModMain+0x74>)
198: f859 3003 ldr.w r3, [r9, r3]
19c: 4619 mov r1, r3
19e: 4b18 ldr r3, [pc, #96] ; (200 <appModMain+0x78>)
1a0: f859 3003 ldr.w r3, [r9, r3]
1a4: 4618 mov r0, r3
1a6: f000 f8bb bl 320 <printf>
1aa: f640 30b8 movw r0, #3000 ; 0xbb8
When loading-up the variable to put into r2, which is going to be passed to printf() as pBuffer, r3 needs to be adjusted, yet it is not (detail below).
We've tried various permutations of -mpic-data-is-text-relative/-mnopic-data-is-text-relative and -msingle-pic-base/-mnosingle-pic-base but none of them make a difference: we just cannot make a pointer reference to a global variable work. Unfortunately we can't change the source code we are compiling, there's quite a large amount of it and some if it is not ours; and of course this is perfectly valid C code.
Can you suggest how to compile a ThreadX Module under GCC so that it runs correctly?
Detail:
In the disassembled output, the contents of 1f8 and 1fc for the example above are:
1f8: 000001bc
1fc: 000001b0
...in the .got section of the disassembled output, these offset are towards the end, here:
Disassembly of section .got:
00006b88 <__ctors_end__>:
...
6d34: 1002c5a8
6d38: 1000025c ; 6b88 + 1b0
6d3c: 00001e15
6d40: 1002c5ac
6d44: 100001d0 ; 6b88 + 1bc
...and 100001d0 in the disassembled output turns out to be:
Disassembly of section .data:
...
100001d0 <pBuffer>:
100001d0: 1000025c
...while 1000025c in the disassembled output turns out to be:
Disassembly of section .bss:
...
1000025c <buffer>:
...
So pBuffer is initialised by the compiler to the un-offsetted address of buffer, and the compiler knows that pBuffer it is a pointer to something in the GOT, yet it did not do anything to add the offset when it generated the code.
We are using ThreadX and ThreadX Modules in our product, have been doing so for many years. So far we have always built under ARMCC. We now need to build the ThreadX Modules under GCC (12.2 release 1).
We have followed the form of your example (i.e. compilation switches
-fpie -fno-plt -mno-pic-data-is-text-relative -msingle-pic-base, no particular linker switches) and in general the code runs, however there is a specific case where these compilation flags do NOT work: when taking the address of a global variable. For instance:...results in a printed output of the form:
In other words
pBufferis not being offset correctly. This is clear when you look at the disassembled code:When loading-up the variable to put into
r2, which is going to be passed toprintf()aspBuffer,r3needs to be adjusted, yet it is not (detail below).We've tried various permutations of
-mpic-data-is-text-relative/-mnopic-data-is-text-relativeand-msingle-pic-base/-mnosingle-pic-basebut none of them make a difference: we just cannot make a pointer reference to a global variable work. Unfortunately we can't change the source code we are compiling, there's quite a large amount of it and some if it is not ours; and of course this is perfectly valid C code.Can you suggest how to compile a ThreadX Module under GCC so that it runs correctly?
Detail:
In the disassembled output, the contents of
1f8and1fcfor the example above are:...in the
.gotsection of the disassembled output, these offset are towards the end, here:...and 100001d0 in the disassembled output turns out to be:
...while 1000025c in the disassembled output turns out to be:
So
pBufferis initialised by the compiler to the un-offsetted address ofbuffer, and the compiler knows thatpBufferit is a pointer to something in the GOT, yet it did not do anything to add the offset when it generated the code.