Subject: g++ exceptions and gprof profiling
To: None <port-arm32@NetBSD.ORG>
From: Adam Gundy <adam@impala.demon.co.uk>
List: port-arm32
Date: 07/07/1997 21:04:50
Hi. After much late night work, grepping of the gcc source code,
and reading the .info files (and some swearing), I've written the
attached (small) patch which allows exceptions to be used with
g++/arm32 - the frame pointer and link register weren't being
located correctly by __builtin_return_address().

(as an aside, don't expect much joy with optimisation -
we'll have to wait for 2.8.0) 

In addition to patching (and compiling) gcc/g++ you'll need to
'borrow' the exception handling code from libgcc2.a which is
created when you build the compiler:

ar x libgcc2.a _eh.o
cp /usr/lib/libgcc.a /usr/lib/libgcc.a.old
ar r /usr/lib/libgcc.a _eh.o
ranlib /usr/lib/libgcc.a

As a side effect of the fix, I discovered that the profiling
support code included with gcc (gmon.c) can be compiled (with the
aid of the second patch).

You need to "gcc -S -O gmon.c" (with a patched gcc), then make
the following minor changes to the assembly output (gmon.s):

1) find the function mcount() in the assembly listing

2) change the "stmfd sp!, {r4 ..." and "ldm..ea sp!, {r4 ..." lines
   (should be four with -O) to include registers 0 to 3 ie.
   "stmfd sp, "{r0, r1, r2, r3, r4 ..."
   (the mcount() provided in libc.a is _broken_ and can't be used -
   it doesn't stack these registers and hence the first four args
   to any function are corrupted)

3) create gmon.o by compiling the modified assembly listing:
   gcc -c gmon.s
   
3) delete (or rename) all the profiling libraries in /usr/lib and
   replace them with links to the normal libs (eg delete libc_p.a
   and make a replacement link to libc.a).
   This is because the profiling libraries seem to have been compiled
   before a (NetBSD) change was made to the compiler and have a
   word of space reserved at the start of each function (which
   unfortunately looks like an instruction to the processor ;-) 
   
You can now profile a program....
 
 * compile with "-pg"
 
 * make sure that "gmon.o" is in your link line so it replaces the
   default one.
 
 * run the program as normal.
 
 * when you're finished, type "gprof <program_name>"
   Pipe the output through c++filt to de-mangle the function names
   if it's a C++ program. 
 
 * if you get a lot of references to "L<number>" try
   "strip -x <program>" (but don't expect to debug it anymore...)
 
Profiling a program seems to generate messages like:
 "impala /netbsd: Using pcb_onfault=f010e484 addr=0000dfb2 st=1c371007
                  curproc=f14dce00"

every so often, and after ten of these messages:                  
 "impala /netbsd: Bummer: OD'ing on onfault_count"

but it doesn't seem to hurt anything.

ok. enough talk. here are the patches:


----8<---Exception handling----8<------

diff -N -c -r gcc-2.7.2.2/config/arm/arm.h gcc-2.7.2.2-riscbsd/config/arm/arm.h
*** config/arm/arm.h         Mon Aug 28 11:17:11 1995
--- gcc-2.7.2.2-riscbsd/config/arm/arm.h Sat Jul 05 15:21:34 1997
***************
*** 334,339 ****
--- 334,352 ----
                       [|  saved f4 value     |]     three words
    r0-r3 are not normally saved in a C function.  */
  
+ /* Define two RTXs which provide offsets into the frame to reach
+    the frame pointer and link register. These make 
+    __builtin_return_address() work. */
+ 
+ /* The frame pointer */
+ #define DYNAMIC_CHAIN_ADDRESS(EXP)  \
+    plus_constant (EXP, -12)
+ 
+ /* The link register. Subtracts 8 rather than 4 because the base
+    is FP+4. */
+ #define RETURN_ADDR_RTX(COUNT,EXP)  \
+    plus_constant (EXP, -8)
+ 
  /* The number of hard registers is 16 ARM + 8 FPU + 1 CC + 1 SFP.  */
  #define FIRST_PSEUDO_REGISTER  27
  

---8<------gprof profiling-------8<----

diff -N -c -r gcc-2.7.2.2/gmon.c gcc-2.7.2.2-riscbsd/gmon.c
*** gcc-2.7.2.2/gmon.c         Thu Aug 31 22:51:55 1995
--- gcc-2.7.2.2-riscbsd/gmon.c Sat Jul 05 12:49:53 1997
***************
*** 43,49 ****
  #include <stdio.h>
  #endif
  
! #include "gmon.h"
  
  extern mcount() asm ("mcount");
  extern char *minbrk asm ("minbrk");
--- 43,51 ----
  #include <stdio.h>
  #endif
  
! #include <unistd.h>
! #include <sys/types.h>
! #include <sys/gmon.h>
  
  extern mcount() asm ("mcount");
  extern char *minbrk asm ("minbrk");
***************
*** 68,73 ****
--- 70,77 ----
  static int s_scale;
      /* see profil(2) where this is describe (incorrectly) */
  #define  SCALE_1_TO_1 0x10000L
+ 
+ #define phdr gmonhdr
  
  #define MSG "No space for profiling buffer(s)\n"
  

---8<---------8<-----
  
Seeya,
 Adam.  
-- 
As the year 2000 approaches, the carefully planned Millenium 'bug'
begins to manifest itself in the computing job market...
Real programmers don't comment their code. If it was hard to write, it
should be harder to modify. These are all my own opinions.