Bug 829187 - ocaml ppc64 backend cannot handle more than around 8 parameters in native C call
Summary: ocaml ppc64 backend cannot handle more than around 8 parameters in native C call
Keywords:
Status: CLOSED RAWHIDE
Alias: None
Product: Fedora
Classification: Fedora
Component: ocaml
Version: rawhide
Hardware: ppc64
OS: Unspecified
unspecified
unspecified
Target Milestone: ---
Assignee: Richard W.M. Jones
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2012-06-06 07:56 UTC by Richard W.M. Jones
Modified: 2012-06-06 13:37 UTC (History)
4 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2012-06-06 12:37:20 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)
test_c.c (1.17 KB, text/x-csrc)
2012-06-06 07:57 UTC, Richard W.M. Jones
no flags Details
test.ml (201 bytes, application/octet-stream)
2012-06-06 07:58 UTC, Richard W.M. Jones
no flags Details

Description Richard W.M. Jones 2012-06-06 07:56:31 UTC
Description of problem:

The ocaml ppc64 backend corrupts arguments if there are more than
around 8 parameters, when calling an external C function in native
code.

Version-Release number of selected component (if applicable):

ocaml-3.12.1-10.fc18.ppc64

How reproducible:

100%

Steps to Reproduce:
1. Download the attached files 'test_c.c' and 'test.ml'
2. Compile using:
   ocamlopt.opt test.ml test_c.c -o test
3. Run using:
   ./run
  
Actual results:

1
2
3
4
5
6
7
8
14
15
0
134340272
629396268
629285660
629399448

Expected results:

It should print the numbers 1 .. 15.

Additional info:

Comment 1 Richard W.M. Jones 2012-06-06 07:57:09 UTC
Created attachment 589756 [details]
test_c.c

Comment 2 Richard W.M. Jones 2012-06-06 07:58:03 UTC
Created attachment 589757 [details]
test.ml

Comment 3 Richard W.M. Jones 2012-06-06 08:42:54 UTC
For additional debugging, use this compile command:

ocamlopt.opt -g -ccopt -g test.ml test_c.c -o test

Then gdb will show symbols at least in the C part:

$ gdb ./test 
(gdb) break test_c
Breakpoint 1 at 0x10004f90: file test_c.c, line 13.
(gdb) run
Starting program: /tmp/test 

Breakpoint 1, test_c (v1=3, v2=5, v3=7, v4=9, v5=11, v6=13, v7=15, v8=17, 
    v9=29, v10=31, v11=0, v12=268680544, v13=551014606424, v14=551014385208, 
    v15=551014612784) at test_c.c:13
13	{
Missing separate debuginfos, use: debuginfo-install glibc-2.15-37.fc17.ppc64
(gdb) bt
#0  test_c (v1=3, v2=5, v3=7, v4=9, v5=11, v6=13, v7=15, v8=17, v9=29, v10=31, 
    v11=0, v12=268680544, v13=551014606424, v14=551014385208, v15=551014612784)
    at test_c.c:13
#1  0x0000000010018fd8 in .caml_c_call ()
#2  0x000000001000296c in camlTest__code_begin ()
#3  0x00000000100023b4 in caml_startup__code_begin ()
#4  0x000000001001915c in .caml_start_program ()
#5  0x0000000010019850 in .caml_main ()
#6  0x0000000010002144 in .main ()

Comment 4 Richard W.M. Jones 2012-06-06 08:57:50 UTC
The registers when caml_c_call is called.  Note that according to
the ppc64 ABI, r3-r10 carry the first 8 parameters:

(gdb) info registers 
r0             0x100023b4	268444596
r1             0xfffffffeb10	17592186039056
r2             0x1003bd60	268680544
r3             0x3	3   # param 1
r4             0x5	5   # param 2
r5             0x7	7   # param 3
r6             0x9	9   # param 4
r7             0xb	11  # param 5
r8             0xd	13  # param 6
r9             0xf	15  # param 7
r10            0x11	17  # param 8
r11            0x10031e58	268639832
r12            0x10018fa4	268537764
r13            0x804b04cc40	551014419520
r14            0x15	21
r15            0x17	23
r16            0x19	25
r17            0x1b	27
r18            0x1d	29
r19            0x1f	31
r20            0x100309f4	268634612
r21            0x100309dc	268634588
r22            0x13	19
r23            0x1800	6144
r24            0xfffb7fd0f50	17590977892176
r25            0x10004f64	268455780
r26            0x10030a5c	268634716
r27            0x10030a74	268634740
r28            0x10030a8c	268634764
r29            0xfffffffed90	17592186039696
r30            0xfffb7dd1000	17590975795200
r31            0xfffb7fd0f48	17590977892168
pc             0x10018fa4	0x10018fa4 <.caml_c_call>
msr            0x900000000002d032	10376293541461807154
cr             0x44000484	1140851844
lr             0x1000296c	0x1000296c <camlTest__code_begin+128>
ctr            0x10018fa4	268537764
xer            0x20000000	536870912
orig_r3        0x2	2
trap           0x700	1792

The remaining parameters are passed on the stack (r1 is sp).  I have
reformatted the output to make the stack layout clearer:

(gdb) x/32x 0xfffffffeb10  # stack pointer
0xfffffffeb10:	0x00000fff	0xffffebc0
                0x00000000	0x00000000
0xfffffffeb20:	0x00000000	0x00000001
                0x00000000	0x00000000
0xfffffffeb30:	0x00000000	0x00000001
                0x00000000	0x1003bd60
0xfffffffeb40:	0x00000fff	0xffffebf0
                0x00000000	0x10030a74
0xfffffffeb50:	0x00000000	0x10030a8c
                0x00000000	0x00000013 # sp+0x48 == param 9
0xfffffffeb60:	0x00000000	0x00000015 # param 10
                0x00000000	0x00000017 # param 11
0xfffffffeb70:	0x00000000	0x00000019 # param 12
                0x00000000	0x0000001b # param 13
0xfffffffeb80:	0x00000000	0x0000001d # param 14  XXX
                0x00000000	0x0000001f # param 15
0xfffffffeb90:	0x00000000	0x00000000
                0x00000000	0x1003bd60
0xfffffffeba0:	0x00000080	0x4b07a658
                0x00000080	0x4b044638
0xfffffffebb0:	0x00000080	0x4b07bf30
                0x00000000	0xffffffff
0xfffffffebc0:	0x00000fff	0xffffec20
                0x00000000	0x00000000
0xfffffffebd0:	0x00000000	0x100023b4
                0x00000000	0x00000000
0xfffffffebe0:	0x00000000	0x00000000
                0x00000000	0x1003bd60
0xfffffffebf0:	0x00000000	0x00000000
                0x00000000	0x00000000
0xfffffffec00:	0x00000000	0x00000000
                0x00000000	0x00000000

XXX == what the C function thinks is parameter 9.

Comment 5 Richard W.M. Jones 2012-06-06 09:39:05 UTC
Notes about parameter passing, derived from the ppc64 ABI:
http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html#PARAM-PASS

(1) The parameter save area starts at sp + 0x30 (sp + 48).

(2) Although the first 8 parameters are passed in r3-r10, space is still
reserved for them in the parameter save area (in case they need to be
spilled by the callee).  Therefore addresses sp + 0x30 .. sp + 0x6f
are reserved, although they are not initialized and therefore contain
random data.

(3) The parameters 9 onwards should appear at sp + 0x70 onwards.
In fact, this is precisely where the C function is looking for them
("XXX" in the comment above).

(4) The OCaml part is NOT saving parameters 9+ at the correct
location.  For some reason it saves them starting at sp + 0x48.

Comment 6 Richard W.M. Jones 2012-06-06 10:10:26 UTC
Note that pure OCaml programs work fine:

$ cat test-ocaml.ml 
open Printf
let test i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 i13 i14 i15 =
  printf "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n"
    i1 i2 i3 i4 i5 i6 i7 i8 i9 i10 i11 i12 i13 i14 i15
let () = test 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
$ ocamlopt.opt test-ocaml.ml -o test-ocaml
File "test-ocaml.ml", line 1, characters 0-1:
Warning 24: bad source file name: "Test-ocaml" is not a valid module name.
$ ./test-ocaml 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Comment 7 Richard W.M. Jones 2012-06-06 10:38:47 UTC
I think I see the problem:

The Cextcall/Iextcall code calls Proc.loc_external_arguments.  But
this function hard codes a parameter offset of 8 (instead of, presumably,
48).  Notice the difference is 40, which also happens to be the
displacement of the stack arguments from where they are expected to be.

http://git.infradead.org/users/dwmw2/ocaml-ppc64.git/blob/HEAD:/asmcomp/power64/proc.ml#l191

I have changed this to 48 and I am recompiling the compiler to see
if this makes a difference.

Comment 8 Richard W.M. Jones 2012-06-06 11:21:24 UTC
Patch:

diff --git a/asmcomp/power64/proc.ml b/asmcomp/power64/proc.ml
index 67f26ab..119ad93 100644
--- a/asmcomp/power64/proc.ml
+++ b/asmcomp/power64/proc.ml
@@ -188,7 +188,7 @@ let poweropen_external_conventions first_int last_int
 let loc_external_arguments =
   match Config.system with
   | "rhapsody" -> poweropen_external_conventions 0 7 100 112
-  | "elf" | "bsd" -> calling_conventions 0 7 100 107 outgoing 8
+  | "elf" | "bsd" -> calling_conventions 0 7 100 107 outgoing 48
   | _ -> assert false
 
 let extcall_use_push = false

Comment 9 David Woodhouse 2012-06-06 12:02:02 UTC
Looks good to me; thanks.

Comment 10 Richard W.M. Jones 2012-06-06 12:37:20 UTC
Fix included in OCaml 3.12.1-11.

However this fix hasn't got completely to the bottom of things.
I still see a segfault in the libguestfs OCaml bindings, so
there is some other issue going on.  Will open another bug if
required.

Comment 11 Richard W.M. Jones 2012-06-06 13:37:15 UTC
The other issue I'm seeing appears to be related
to an existing bug:

https://bugzilla.redhat.com/show_bug.cgi?id=826649#c5


Note You need to log in before you can comment on or make changes to this bug.