gcc: Thumb interworking and weakly linked functions
V, Aneesh
aneesh at ti.com
Mon Feb 20 05:50:34 UTC 2012
+ linaro-toolchain
Hello Ulrich,
I want to revisit this old thread. Sorry for the sloppy follow-up. But,
this time around I have more data.
On Tue, Mar 15, 2011 at 9:00 PM, Ulrich Weigand
<Ulrich.Weigand at de.ibm.com> wrote:
> Aneesh V <aneesh at ti.com> wrote:
>
>> I was trying to build u-boot in Thumb2 for OMAP4. Everything was fine
>> until I added some patches recently. One of these patches introduced an
>> API (let's say foo()) that has a weakly linked alias(let's say
>> __foo()) and a strongly linked implementation(the real foo()) in an
>> assembly file.
>>
>> Although I give -mthumb and -mthumb-interwork for all the files,
>> apparently GCC generates ARM code for assembly files. In the final
>> image foobar() calls foo() using a BL. Since foobar() is in Thumb and
>> foo() in ARM, it ends up crashing. Looks like foobar() assumed foo()
>> to be Thumb because __foo() is Thumb.
>
> I'm unable to reproduce this. Do you have a complete test case?
>
> I've tried with the following small example:
>
> foo1.c:
>
> extern void foo (void) __attribute__ ((weak, alias ("__foo")));
>
> void __foo (void)
> {
> }
>
> int main (void)
> {
> foo ();
> }
>
> foo2.S:
> .text
> .align 2
> .global foo
> .type foo, %function
> foo:
> push {r7}
> add r7, sp, #0
> mov sp, r7
> pop {r7}
> bx lr
> .size foo, .-foo
>
> When building just "gcc foo1.c", I get:
>
> 0000835c <__foo>:
> 835c: b480 push {r7}
> 835e: af00 add r7, sp, #0
> 8360: 46bd mov sp, r7
> 8362: bc80 pop {r7}
> 8364: 4770 bx lr
> 8366: bf00 nop
>
> 00008368 <main>:
> 8368: b580 push {r7, lr}
> 836a: af00 add r7, sp, #0
> 836c: f7ff fff6 bl 835c <__foo>
> 8370: 4618 mov r0, r3
> 8372: bd80 pop {r7, pc}
>
> When building both files "gcc foo1.c foo2.S", I get instead:
>
> 00008368 <main>:
> 8368: b580 push {r7, lr}
> 836a: af00 add r7, sp, #0
> 836c: f000 e802 blx 8374 <foo>
> 8370: 4618 mov r0, r3
> 8372: bd80 pop {r7, pc}
>
> 00008374 <foo>:
> 8374: e92d0080 push {r7}
> 8378: e28d7000 add r7, sp, #0
> 837c: e1a0d007 mov sp, r7
> 8380: e8bd0080 pop {r7}
> 8384: e12fff1e bx lr
>
>
> So it seems to me the linker is handling this correctly ...
>
> (This is on Ubuntu Natty using system gcc and binutils.)
I could reproduce the problem on older tool-chain(Sourcery G++ Lite
2010q1-202) [1] with a modified version of your sample code:
a.c:
====
extern void foo (void) __attribute__ ((weak, alias ("__foo")));
void __foo (void)
{
}
extern void call_foo(void);
int main (void)
{
call_foo ();
}
b.S:
====
.text
.align 2
.global foo
foo:
push {r7}
add r7, sp, #0
mov sp, r7
pop {r7}
bx lr
.size foo, .-foo
c.S
.text
.align 2
.global call_foo
call_foo:
bl foo
bx lr
.global __aeabi_unwind_cpp_pr0
__aeabi_unwind_cpp_pr0:
bx lr
Now, I build them using the following commands, which is similar to
what U-Boot does:
arm-none-linux-gnueabi-gcc -mthumb -mthumb-interwork -c a.c
arm-none-linux-gnueabi-gcc -mthumb -mthumb-interwork -c b.S
arm-none-linux-gnueabi-gcc -mthumb -mthumb-interwork -c c.S
arm-none-linux-gnueabi-ld -r a.o -o alib.o
arm-none-linux-gnueabi-ld -r b.o -o blib.o
arm-none-linux-gnueabi-ld -r c.o -o clib.o
arm-none-linux-gnueabi-ld --start-group clib.o alib.o blib.o
--end-group -o a.out
armobjdump -S --reloc a.out
You will get something like:
00008094 <call_foo>:
8094: fa000006 blx 80b4 <foo>
8098: e12fff1e bx lr
Please note that that the 'blx' is not correct. Now, do the following change:
diff --git a/b.S b/b.S
index e0f2de9..96dba1f 100644
--- a/b.S
+++ b/b.S
@@ -1,5 +1,6 @@
.text
.align 2
+.type foo, %function
.global foo
foo:
push {r7}
And build it again the same way and you will see:
00008094 <call_foo>:
8094: eb000006 bl 80b4 <foo>
8098: e12fff1e bx lr
I can't reproduce this on Linaro GCC 2012.01, so looks like the problem
is solved in recent tool-chains. However, sadly I could reproduce a
different but similar problem with Linaro GCC 2012.01. This time the
call is from C(Thumb) to assembly(ARM) and no weakly linked symbols are
involved.
a.c:
====
int main (void)
{
foo ();
}
b.S:
====
.text
.align 2
.global foo
foo:
push {r7}
add r7, sp, #0
mov sp, r7
pop {r7}
bx lr
.size foo, .-foo
.global __aeabi_unwind_cpp_pr0
__aeabi_unwind_cpp_pr0:
bx lr
arm-linux-gnueabi-gcc -mthumb -mthumb-interwork -c a.c
arm-linux-gnueabi-gcc -mthumb -mthumb-interwork -c b.S
arm-linux-gnueabi-ld -r a.o -o alib.o
arm-linux-gnueabi-ld -r b.o -o blib.o
arm-linux-gnueabi-ld --start-group alib.o blib.o --end-group -o a.out
arm-linux-gnueabi-objdump -S --reloc a.out
gives:
8076: af00 add r7, sp, #0
8078: f000 f802 bl 8080 <foo>
807c: 4618 mov r0, r3
It should have been "blx 8080 <foo>", isn't it? Again, %function
solves it.
I agree that not marking the assembly functions ' %function' is a problem
in the code, so it's not a critical bug. But I would've been happier if
the linker refused to link it rather than branching with the wrong
instruction. Isn't that a problem?
Problem No:2
*************
Linaro GCC 2012.01 is giving a new problem w.r.to Thumb build
that is not existing in Sourcery G++ Lite 2010q1-202. However, I
couldn't reproduce this problem with a small program like above. So,
let me give you reference to the original u-boot code that shows the
problem and steps to reproduce it.
tree: git://github.com/aneeshv/u-boot.git
branch: thumb
The above branch has mainline u-boot with 4 additional patches from me
for enabling Thumb build. You can build it like this:
make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm distclean
make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm omap4_sdp4430
This builds two images u-boot and u-boot-spl. SPL is a tiny u-boot that
runs from internal RAM and loads the u-boot to SDRAM. Now, please have
a look at the map file of u-boot-spl which is at: spl/u-boot-spl.map
I see the following in my map file:
/spl/u-boot-spl.map:
=================
.rodata.wkup_padconf_array_essential_4460
0x40309583 0x4 board/ti/sdp4430/libsdp4430.o
0x40309583 wkup_padconf_array_essential_4460
.rodata.wkup_padconf_array_essential
0x40309587 0xc board/ti/sdp4430/libsdp4430.o
0x40309587 wkup_padconf_array_essential
.rodata.core_padconf_array_essential
0x40309593 0x60 board/ti/sdp4430/libsdp4430.o
0x40309593 core_padconf_array_essential
Please note that the .rodata symbols have odd addresses. These arrays
actually need to be aligned at least to half-word boundary. In fact, in
the image I verified that they are put at even addresses. So, the
symbols have been kept as real address +1. I understand that this is
the convention for Thumb functions. I guess the tool-chain did it for
data too?? And I am getting unaligned access aborts on accessing them.
I notice that this doesn't happen with all .rodata. symbols in the
image. I couldn't see any difference between working and non-working
files nor any difference in the command used to build them!
Well, this doesn't happen if I don't use "-fdata-sections" in gcc
options. So, apply the following patch and you will see that those
symbols have even addresses now.
diff --git a/config.mk b/config.mk
index ddaa477..723286a 100644
--- a/config.mk
+++ b/config.mk
@@ -190,7 +190,7 @@ CPPFLAGS := $(DBGFLAGS) $(OPTFLAGS) $(RELFLAGS) \
# Enable garbage collection of un-used sections for SPL
ifeq ($(CONFIG_SPL_BUILD),y)
-CPPFLAGS += -ffunction-sections -fdata-sections
+CPPFLAGS += -ffunction-sections
LDFLAGS_FINAL += --gc-sections
endif
/spl/u-boot-spl.map:
=================
.rodata 0x40309204 0x38c board/ti/sdp4430/libsdp4430.o
0x40309204 core_padconf_array_essential
0x40309264 wkup_padconf_array_essential
0x40309270 wkup_padconf_array_essential_4460
0x40309274 core_padconf_array_non_essential
0x40309540 wkup_padconf_array_non_essential
0x40309588 wkup_padconf_array_non_essential_4430
Will you be able to look into these?
Thanks,
Aneesh
[1] Sourcery G++ Lite 2010q1-202
arm-none-linux-gnueabi-gcc (Sourcery G++ Lite 2010q1-202) 4.4.1
GNU ld (Sourcery G++ Lite 2010q1-202) - binutils 2.19.51.20090709
[2] Linaro 4.6-2012.01
arm-linux-gnueabi-gcc (crosstool-NG linaro-1.13.1-2012.01-20120125 -
Linaro GCC 2012.01) 4.6.3 20120105 (prerelease)
GNU ld (crosstool-NG linaro-1.13.1-2012.01-20120125 - Linaro GCC 2012.01) 2.22
More information about the linaro-dev
mailing list