Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot build on Mac OS X 32-bit with Xcode 4.0.2 #5268

Closed
vicuna opened this issue May 17, 2011 · 11 comments
Closed

Cannot build on Mac OS X 32-bit with Xcode 4.0.2 #5268

vicuna opened this issue May 17, 2011 · 11 comments
Assignees
Labels

Comments

@vicuna
Copy link

@vicuna vicuna commented May 17, 2011

Original bug ID: 5268
Reporter: brendan
Assigned to: @damiendoligez
Status: closed (set by @xavierleroy on 2015-12-11T18:08:32Z)
Resolution: not a bug
Priority: normal
Severity: crash
Version: 3.12.0
Category: ~DO NOT USE (was: OCaml general)
Monitored by: jeffsco "Pascal Cuoq"

Bug description

Ocaml 3.12.0 builds fine on Mac OS X (10.6.7) with Xcode 4.0.2 in 64-bit mode. Attempting to build it in 32-bit mode results in:

../ocamlcompopt.sh -nostdlib unix.cmxa -g -I stdlib -I ../otherlibs/unix ocamlbuild/ocamlbuild_executor.cmx ocamlbuild/ocamlbuild_pack.cmx ocamlbuild/ocamlbuild_unix_plugin.cmx ocamlbuild/ocamlbuild.cmx -o ocamlbuild/ocamlbuild.native
ld: in ocamlbuild/ocamlbuild_pack.o, in section __DATA,__data reloc 1: sectionForAddress(0x4028458) address not in any section for architecture i386

I've tried -cc "gcc-4.0 -m32" -as "as -arch i386" -aspp "gcc-4.0 -m32 -c" as well as gcc-4.2

File attachments

@vicuna
Copy link
Author

@vicuna vicuna commented May 31, 2011

Comment author: jhowarth

The darwin linker developer had the following observations on this problem...

The problem is in ocamlbuild_pack.o. There is a wacky relocation:

[/tmp/ocaml_bug]> otool -rv ocamlbuild_pack.o | grep -A4 'Relocation information (__DATA,__data)'
Relocation information (__DATA,__data) 10621 entries
address pcrel length extern type scattered symbolnum/value
000000c0 False long False VANILLA False 1 (__TEXT,__text)
000000dc False long n/a SECTDIF True 0x04028458
False long n/a PAIR True 0x00028450
[/tmp/ocaml_bug]> size -l ocamlbuild_pack.o

Segment : 301288 (vmaddr 0x0 fileoff 424)
Section (__TEXT, __text): 164654 (addr 0x0 offset 424)
Section (__IMPORT, __pointers): 68 (addr 0x28330 offset 165080)
Section (__DATA, __data): 136564 (addr 0x28374 offset 165148)
total 301286
total 301288
[/tmp/ocaml_bug]>

The reloc 0xDC bytes into the __DATA/__data section references 0x04028458 which you can see (via size -l output) is not a valid address in the object file.

Interestingly, if you lop of the high bit (to become 0x00028458), the address is valid. Is this a single bit error somewhere?

...later analyzing the component object files making up ocamlbuild_pack.o, he observed...

[/tmp/ocaml_bug_pt2]> otool -rv discard_printf.o
discard_printf.o:
Relocation information (__TEXT,__text) 4 entries
address pcrel length extern type scattered symbolnum/value
00000039 False long False VANILLA False 2 (__DATA,__data)
00000034 False long False VANILLA False 2 (__DATA,__data)
0000001c True long True VANILLA False _camlFormat__ifprintf_1768
00000017 False long True VANILLA False _camlFormat
Relocation information (__DATA,__data) 4 entries
address pcrel length extern type scattered symbolnum/value
00000028 False long n/a LOCSDIF True 0x00000078

     False long   n/a    PAIR    True      0x00000070

0000001c False long False VANILLA False 1 (__TEXT,__text)
0000000c False long False VANILLA False 1 (__TEXT,__text)

[/tmp/ocaml_bug_pt2]> otool -s __DATA __data discard_printf.o
discard_printf.o:
Contents of (__DATA,__data) section
00000048 00 04 00 00 00 00 00 00 f7 08 00 00 10 00 00 00
00000058 03 00 00 00 00 00 00 00 01 00 00 00 20 00 00 00
00000068 11 00 01 00 00 00 00 00 08 00 00 04 91 f1 00 00
00000078 6f 63 61 6d 6c 62 75 69 6c 64 2f 64 69 73 63 61
00000088 72 64 5f 70 72 69 6e 74 66 2e 6d 6c 00 00 00 00
[/tmp/ocaml_bug_pt2]>

The issue is at _camlOcamlbuild_pack__Discard_printf__frametable + 16. There is a sect-diff reloc at that address (0x70 = __data + 0x28). The problem is the content
+(in bold above) is 0x0400008.

@vicuna
Copy link
Author

@vicuna vicuna commented Jun 1, 2011

Comment author: jhowarth

Further analysis of the offending discard_printf.o by adding -S to ../ocamlcompopt.sh and executing...

[MacPro-2:ocaml-3.12.0-2/ocaml-3.12.0/_build] root# ../ocamlcompopt.sh -nostdlib -c -g -annot -rectypes -warn-error A -w L -w R -w Z -I ../otherlibs/unix -for-pack Ocamlbuild_pack -I ocamlbuild -I stdlib -o ocamlbuild/discard_printf.cmx ocamlbuild/discard_printf.ml

...by the darwin linker maintainer is that...

The issue is this:

    .align  2
    .long        L200000 - . + 0x4000000   #<--- what is it trying to do here?
    .long         0xf191

L200000:
.ascii "ocamlbuild/discard_printf.ml\0"

The label L200000 is 8 bytes ahead, and (.) means current location, so (L200000 - . ) means 8. But the assembler does not know this a assembly time constant, so passes it on to the linker. The linker bug is in handling a degenerate relocation which is the difference of the same location plus a huge constant.

@vicuna
Copy link
Author

@vicuna vicuna commented Jun 1, 2011

Comment author: jhowarth

Uploaded assembly file for discard_printf.s from i386 darwin which contains the offending assembly.

@vicuna
Copy link
Author

@vicuna vicuna commented Jun 3, 2011

Comment author: jeffsco

I'm trying to build a 32-bit version of 3.12.0 under Xcode 4.0.2, and I see the same problem exactly. I'd love to see this problem resolved. I'm running OCaml code in the iPhone Simulator, for which I need 32-bit code. In the meantime I'll downgrade to previous Xcode (3.2.5), which seems to be working.

@vicuna
Copy link
Author

@vicuna vicuna commented Jun 3, 2011

Comment author: jhowarth

Am I correct to assume that it is impossible to get ocamlopt to produce a preprocessed source file rather than just the assembly file? I was hoping a preprocessed source file would contain clues to why...

    .align 2
    .long L200000 - . + 0x4000000 #<--- what is it trying to do here?
    .long 0xf191

L200000:
.ascii "ocamlbuild/discard_printf.ml\0"

this is present in the generated assembly.

@vicuna
Copy link
Author

@vicuna vicuna commented Jun 4, 2011

Comment author: @xavierleroy

I very much hope this regression in Xcode will be fixed, since we have here a useful idiom that has been working flawlessy with earlier versions of Xcode and indeed with any other assembler/linker combination we've tested on other systems.

FYI, "what it is trying to do here" is to store debugging information that is carefully packed in a 64-bit word according to the pseudo-C-struct-with-bitfields below:

struct debuginfo {
int flags: 2;
int filename_offset: 24;
int char_end: 10;
int char_start: 8;
int lineno: 20;
};

The "filename_offset" field encodes a pointer to a string literal, but to save bits it contains the difference between the string literal and the beginning of the struct. In pseudo-C again, the debugging info 'file "foo.ml", line 15, characters 25-65' would be initialized as follows:

char filename[] = "foo.ml";

struct debuginfo dbg1 = {
0,
(char *) &dbg1 - filename;
65,
25,
15
};

In assembly, that gives:

dbg1:
.long filename - . + 0x4000000
.long 0xf191
filename:
.ascii "foo.ml"

Two things surprise me in the explanations given in previous notes:
1- that the difference "Lfilename - ." is not computed immediately by the assembler (it certainly can compute it!)
2- that it makes a difference to the linker that the offset "+ 0x4000000" is big or small: shouldn't any 32-bit integer be accepted here?

@vicuna
Copy link
Author

@vicuna vicuna commented Jun 4, 2011

Comment author: jhowarth

The response from the darwin linker developer was...

It is a linker bug. I've already fixed it. It may just take awhile to make it way into a release.

There is a work around, the assembly could be changed to:

dbg1:
.set Ldelta, Lfilename - .
.long Ldelta + 0x4000000
.long 0xf191
Lfilename:
.ascii "foo.ml"

The .set directive forces the delta value to be computed at assembly time.

@vicuna
Copy link
Author

@vicuna vicuna commented Jun 7, 2011

Comment author: @xavierleroy

Thanks for the info.

There is a work around [...] The .set directive forces the delta value to be computed at assembly time.

That's good to know. Would it make a difference if Lfilename was defined before "Lfilename - . + 0x40000000" is computed? That would be easy to arrange and might help reducing the number of relocs on other platforms as well. (Wild guess.)

@vicuna
Copy link
Author

@vicuna vicuna commented Jun 11, 2011

Comment author: @xavierleroy

A follow-up on the two workarounds proposed so far:

1- Define Lfilename before "Lfilename - . + 0x40000000" is computed.
Not so easy to arrange as I thought. (Sign issues, forcing more extensive changes that I can do in time for the next release.)

2- Use ".set Ldelta, Lfilename - . ; .long Ldelta + 0x4000000".
Doesn't work with Xcode 3.2: Ldelta is always set to 8 no matter how far ahead Lfilename is.

So I'm afraid we are stuck for the moment. The few OCaml users who need to compile it in 32 bits under MacOS X will have to wait for an upgrade to XCode 4.0.2 or downgrade to an earlier version of XCode.

@vicuna
Copy link
Author

@vicuna vicuna commented Aug 3, 2011

Comment author: @damiendoligez

It looks like Apple fixed their linker: OCaml 3.12.1 works on Mac OS 10.7 (Lion) with XCode 4.1 after applying the patch found in #4863.

@vicuna
Copy link
Author

@vicuna vicuna commented Dec 30, 2012

Comment author: Pascal Cuoq

Thanks everyone involved in this report for documenting the trail.

For whoever will pass next, if, say, you have tasted the command-line tools for Snow Leopard (https://github.com/kennethreitz/osx-gcc-installer/ ) and are loath to download the four and a half Gigabytes that is Xcode 3.2.6, solution 2 in comment 0006002 can be implemented in OCaml 4.00.1 with the patch below.

OCaml 4.00.1, thus patched, compiled with the command-line tools at https://github.com/downloads/kennethreitz/osx-gcc-installer/GCC-10.6.pkg , works fine to the best of my testing.

macbook:ocaml-4.00.1 pascal$ diff -u asmcomp/i386/emit.mlp{,}
--- asmcomp/i386/emit.mlp
2012-07-30 20:59:07.000000000 +0200
+++ asmcomp/i386/emit.mlp 2012-12-30 21:51:57.000000000 +0100
@@ -1020,7 +1020,7 @@
efa_word = (fun n -> .long {emit_int n}\n);
efa_align = emit_align;
efa_label_rel = (fun lbl ofs ->

  •                       `	.long	{emit_label lbl} - . + {emit_int32 ofs}\n`);
    
  •                       `	.set Ldelta, {emit_label lbl} - . \n .long	Ldelta + {emit_int32 ofs}\n`);
     efa_def_label = (fun l -> `{emit_label l}:\n`);
     efa_string = (fun s ->
       let s = s ^ "\000" in
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants