NetBSD-Users archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
gprof SEGV issue for GCC-4.5.X toolchain.
Dear All,
I have build the NetBSD-5.1 library by compiling it for ARMv7a (Cortex
architecture)
using the GNU GCC-4.5 toolchain.
Now when I tried to build a sample scenario "hello.c" with profiling
options "-pg" for gprof analysis.
The following undefined reference error was noticed.
$ cat hello.c
{{{
void hello(int i)
{
}
int main(void)
{
hello(1);
}
}}}
$ gcc -march=armv7-a -pg hello.c -o hello.exe -lgprof
{{{
/tmp/ccyXENx3.o: In function `hello':
hello.c:(.text+0x8): undefined reference to `__gnu_mcount_nc'
/tmp/ccyXENx3.o: In function `main':
hello.c:(.text+0x30): undefined reference to `__gnu_mcount_nc'
collect2: ld returned 1 exit status
}}}
Initial investigation shows that GCC now uses a new EABI-compatible
profiling interface for EABI targets.
This requires a function "__gnu_mcount_nc".
I have checked that GCC 4.3.3 does not use the implementaiton of
"__gnu_mcount_nc", it uses old "_mcount" implementation.
But in gcc 4.4.x and later the name and calling convention for
function profiling on ARM changed.
Now the new implementation uses "__gnu_mcount_nc".
So the solution to resolve this issue is to add this new profiling
hook "__gnu_mcount_nc" into NetBSD library.
The fix is:
$ cat src/sys/arch/arm/include/profile.h
{{{
-#define MCOUNT_ASM_NAME "mcount"
+#define MCOUNT_ASM_NAME "__gnu_mcount_nc"
}}}
With this fix "hello.c" was built and the build issue is resolved:
$ gcc -march=armv7-a -pg hello.c -o hello.exe -lgprof
Execution on Target (BeagleBoard) gives SEGV as follows:
{{{
-bash-3.2# gdb ./hello
(gdb) r
Starting program: /home/amol/hello
Program received signal SIGSEGV, Segmentation fault.
0x00010648 in _GLOBAL_OFFSET_TABLE_ ()
(gdb) bt
#0 0x00010648 in _GLOBAL_OFFSET_TABLE_ ()
#1 0x00010648 in _GLOBAL_OFFSET_TABLE_ ()
}}}
I have further investigated this issue as follows:
-bash-3.2# gdb ./hello
{{{
(gdb) b main
Breakpoint 1 at 0x85a0
(gdb) b hello
Breakpoint 2 at 0x857c
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/amol/work_armv7a
Breakpoint 1, 0x000085a0 in main ()
(gdb) c
Continuing.
Breakpoint 2, 0x0000857c in hello ()
(gdb) si
0x00008580 in hello ()
(gdb)
0x00008584 in hello ()
(gdb) disassemble
Dump of assembler code for function hello:
0x0000857c <+0>: push {r11} ; (str r11, [sp, #-4]!)
0x00008580 <+4>: add r11, sp, #0
=> 0x00008584 <+8>: sub sp, sp, #12
0x00008588 <+12>: push {lr}
0x0000858c <+16>: bl 0x83bc <__gnu_mcount_nc>
0x00008590 <+20>: str r0, [r11, #-8]
0x00008594 <+24>: add sp, r11, #0
0x00008598 <+28>: pop {r11}
0x0000859c <+32>: bx lr
End of assembler dump.
(gdb)
0x4003f45c in __gnu_mcount_nc () from /home/amol/TEST_GPROF/lib/libgprof.so
(gdb) disassemble
Dump of assembler code for function __gnu_mcount_nc:
=> 0x4003f45c <+0>: push {r0, r1, r2, r3, r12, lr}
0x4003f460 <+4>: teq r0, r0
0x4003f464 <+8>: teq pc, pc
0x4003f468 <+12>: ldr r0, [r11, #-4]
0x4003f46c <+16>: moveq r1, lr
0x4003f470 <+20>: bicne r1, lr, #-67108861 ; 0xfc000003
0x4003f474 <+24>: bl 0x4003ea70
0x4003f478 <+28>: pop {r0, r1, r2, r3, lr, pc}
(gdb) si
0x4003f460 in __gnu_mcount_nc () from /home/amol/TEST_GPROF/lib/libgprof.so
(gdb) i r
r0 0x1 1
r1 0xbe9c2da4 -1097060956
r2 0xbe9c2dac -1097060948
r3 0x85a0 34208
r4 0xbe9c2da4 -1097060956
r5 0xbe9c2dac -1097060948
r6 0x1 1
r7 0x84f0 34032
r8 0x40039000 1073975296
r9 0x0 0
r10 0x40031f40 1073946432
r11 0xbe9c2d58 -1097061032
r12 0x106d8 67288
sp 0xbe9c2d30 0xbe9c2d30
lr 0x8590 34192
pc 0x4003f460 0x4003f460 <__gnu_mcount_nc+4>
cpsr 0xa0000010 -1610612720
(gdb) x/8xw $sp
0xbe9c2d30: 0x00000001 0xbe9c2da4 0xbe9c2dac 0x000085a0
0xbe9c2d40: 0x000106d8 0x00008590 0x000085b8 0xbe9c2dac
(gdb) si
(gdb)
0x4003ea70 in ?? () from /home/amol/TEST_GPROF/lib/libgprof.so
(gdb)
0x4003ea74 in ?? () from /home/amol/TEST_GPROF/lib/libgprof.so
(gdb)
0x4003ea78 in ?? () from /home/amol/TEST_GPROF/lib/libgprof.so
(gdb)
0x4003f47c in _mcount () from /home/amol/TEST_GPROF/lib/libgprof.so
(gdb)
0x4003f478 in __gnu_mcount_nc () from /home/amol/TEST_GPROF/lib/libgprof.so
(gdb) disassemble
Dump of assembler code for function __gnu_mcount_nc:
0x4003f45c <+0>: push {r0, r1, r2, r3, r12, lr}
0x4003f460 <+4>: teq r0, r0
0x4003f464 <+8>: teq pc, pc
0x4003f468 <+12>: ldr r0, [r11, #-4]
0x4003f46c <+16>: moveq r1, lr
0x4003f470 <+20>: bicne r1, lr, #-67108861 ; 0xfc000003
0x4003f474 <+24>: bl 0x4003ea70
=> 0x4003f478 <+28>: pop {r0, r1, r2, r3, lr, pc}
(gdb) x/8xw $sp
0xbe9c2d30: 0x00000001 0xbe9c2da4 0xbe9c2dac 0x000085a0
0xbe9c2d40: 0x000106d8 0x00008590 0x000085b8 0xbe9c2dac
(gdb) x 0x000085a0
0x85a0 <main>: 0xe92d4800
===> return address of main() function
(gdb) x 0x000106d8
0x106d8 <_GLOBAL_OFFSET_TABLE_+20>: 0x4003f45c ===> GOT address
(gdb) x 0x00008590
0x8590 <hello+20>: 0xe50b0008
===> return address of hello() function
(gdb) si
0x00008590 in hello ()
(gdb) i r
r0 0x1 1
r1 0xbe9c2da4 -1097060956
r2 0xbe9c2dac -1097060948
r3 0x85a0 34208
r4 0xbe9c2da4 -1097060956
r5 0xbe9c2dac -1097060948
r6 0x1 1
r7 0x84f0 34032
r8 0x40039000 1073975296
r9 0x0 0
r10 0x40031f40 1073946432
r11 0xbe9c2d58 -1097061032
r12 0x4004843c 1074037820
sp 0xbe9c2d48 0xbe9c2d48
lr 0x106d8 67288
pc 0x8590 0x8590 <hello+20>
cpsr 0x20000010 536870928
(gdb) si
0x00008594 in hello ()
(gdb) si
0x00008598 in hello ()
(gdb) si
0x0000859c in hello ()
(gdb) disassemble
Dump of assembler code for function hello:
0x0000857c <+0>: push {r11} ; (str r11, [sp, #-4]!)
0x00008580 <+4>: add r11, sp, #0
0x00008584 <+8>: sub sp, sp, #12
0x00008588 <+12>: push {lr}
0x0000858c <+16>: bl 0x83bc <__gnu_mcount_nc>
0x00008590 <+20>: str r0, [r11, #-8]
0x00008594 <+24>: add sp, r11, #0
0x00008598 <+28>: pop {r11}
=> 0x0000859c <+32>: bx lr
(gdb) x $lr
0x106d8 <_GLOBAL_OFFSET_TABLE_+20>: 0x4003f45c
(gdb) si
0x000106d8 in _GLOBAL_OFFSET_TABLE_ ()
(gdb) si
Program received signal SIGSEGV, Segmentation fault.
0x000106d8 in _GLOBAL_OFFSET_TABLE_ ()
}}}
From the above debug log it is confirmed that “lr” contains
“_GLOBAL_OFFSET_TABLE_” address
instead of return address of main() function. And when hello()
function returns by calling "bx lr",
"PC" points to GOT, causes SEGV.
FIX:
-----
To resolve this issue the MCOUNT implementation needs to be modify as follows.
$ cat src/sys/arch/arm/include/profile.h
{{{
@@ -38,7 +38,7 @@
* prologue.
*/
-#define MCOUNT_ASM_NAME "__mcount"
+#define MCOUNT_ASM_NAME "__gnu_mcount_nc"
#ifdef PIC
#define PLTSYM "(PLT)"
#endif
@@ -56,7 +56,7 @@
/* \
* Preserve registers that are trashed during mcount \
*/ \
- __asm("stmfd sp!, {r0-r3, ip, lr}"); \
+ __asm("stmfd sp!, {r0-r3, lr}"); \
/* Check what mode we're in. EQ => 32, NE => 26 */ \
__asm("teq r0, r0"); \
__asm("teq pc, r15"); \
@@ -80,7 +80,8 @@
/* \
* Restore registers that were trashed during mcount \
*/ \
- __asm("ldmfd sp!, {r0-r3, lr, pc}");
+ __asm("ldmfd sp!, {r0-r3, ip, lr}"); \
+ __asm("bx ip");
#ifdef _KERNEL
#ifdef __PROG26
}}}
In MCOUNT , “r12” is not required to save on stack. Since after return
from "_mcount", it should be
pop with return address i.e. the value of “lr” register which was
pushed before call to "_mcount".
Similarly, “ lr” needs to poped with the return address of main() function.
Then “r12” register contains move into “pc” for returning back to
hello() function.
With this fix patch the gmon profiling working fine without any issue.
Please review the fix patch and let me know if there are any issues.
Thank You,
Amol Pise
Home |
Main Index |
Thread Index |
Old Index