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

options -nodynlink and -fno-PIC together produce assembler errors for MSVC64 #6594

Closed
vicuna opened this issue Oct 3, 2014 · 12 comments
Closed

Comments

@vicuna
Copy link

vicuna commented Oct 3, 2014

Original bug ID: 6594
Reporter: @oandrieu
Assigned to: @mshinwell
Status: closed (set by @mshinwell on 2016-12-08T15:57:46Z)
Resolution: duplicate
Priority: normal
Severity: major
Platform: amd64
OS: Win64
OS Version: Win7
Version: 4.02.0+beta1 / +rc1
Target version: later
Category: back end (clambda to assembly)
Monitored by: @jmeber

Bug description

I tried compiling with MSVC11 (Visual 2012) 64 bits, either option works fine but the two together seem to produce assembler errors as soon as the .ml file is large enough.

Steps to reproduce

  1. edit stdlib/Makefile.shared to add -nodynlink -fno-PIC -verbose to COMPFLAGS
  2. touch stdlib/pervasives.ml
  3. make libraryopt

? I get Assembler error: error A2084: constant value too large

@vicuna
Copy link
Author

vicuna commented Oct 6, 2014

Comment author: @oandrieu

Apparently it's the Istore_symbol instruction that causes the issue (in asmcomp/amd64/emit_nt.mlp):

| Lop(Ispecific(Istore_symbol(s, addr, _))) ->
    assert (not !pic_code);
add_used_symbol s;
    `	mov	QWORD PTR {emit_addressing addr i.arg 0}, OFFSET {emit_symbol s}\n`

vs. the non-windows version:

| Lop(Ispecific(Istore_symbol(s, addr, _))) ->
    assert (not !pic_code && not !Clflags.dlcode);
    `	movq	${emit_symbol s}, {emit_addressing addr i.arg 0}\n`

@vicuna
Copy link
Author

vicuna commented Mar 11, 2015

Comment author: @alainfrisch

Hi Olivier,

Commit 15900 on trunk changes how symbols are addressed on Win64. This was mostly done to support loading .cmxs at arbitrary location in the memory space (otherwise, flexdll would fail at load time to relocate symbols which end up too far). But I suspect this could fix since the movabsq instruction is now used. Can you try?

@vicuna
Copy link
Author

vicuna commented Mar 11, 2015

Comment author: @oandrieu

Hi Alain,

thanks for looking into this.

Well no it doesn't seem to fix it since only X86_gas uses movabsq, X86_masm still emits a plain mov :)

Now from what I understand movabs is a GAS mnemonic (rather than a Intel-documented one), I'm not sure what the ml64 equivalent is ...

@vicuna
Copy link
Author

vicuna commented Mar 11, 2015

Comment author: @alainfrisch

The mnemonic is simply "MOV". Normally ml64 picks the right instruction if the operand is large enough. In that case, the operand is a symbol. I will need to have a closer look at how to fix this...

(FWIW, LexiFi uses a binary code emitter, which means we choose our instructions precisely and don't rely on external assemblers.)

@vicuna
Copy link
Author

vicuna commented Mar 12, 2015

Comment author: @alainfrisch

Out of curiosity:

  1. why do you compile with -nodynlink and -fno-PIC?
  2. How big is the .ml file?

@vicuna
Copy link
Author

vicuna commented Mar 12, 2015

Comment author: @oandrieu

  1. Well, first I'm not 100% clear on the difference between these two options. It's just that I don't need/use dynlink and I thought that using these options would yield the plainest, simplest assembler output.

  2. size of the .ml doesn't appear to be a factor ... There's the issue with stdlib pervasives.ml

@vicuna
Copy link
Author

vicuna commented Mar 12, 2015

Comment author: @alainfrisch

  1. -nodynlink means that the code is not intended to be linked into a .cmxs file and then dynamically loaded; and -fno-PIC that we don't require it to be position-independant. Some systems require dynamically loaded code to be position-independant (so none of -nodynlink and -fno-PIC can be used if we want to use Dynlink), but not always. Under Windows, this is rather the opposite:
    flexdll needs to patch the loaded code, so it doesn't really matter that it is position-independant or not (position-independant is useful to allow physically sharing of pages, which is not possible under Windows anyway). So without -nodynlink and without -fno-PIC, the generated code is not position-independant.

I'm wondering whether we should just ignore -nodynlink and -fno-PIC under Windows. Can you confirm you don't have any problem when you don't use these options?

  1. Ah, I missed the fact about pervasives and I was confused by "as soon as the .ml file is large enough".

@vicuna
Copy link
Author

vicuna commented Mar 12, 2015

Comment author: @oandrieu

Yes, no problem with no option, or either of the option alone. Only when they are both present.

The problematic asm then looks like this:
mov QWORD PTR [rbx], DWORD OFFSET camlPervasives__loop_1150

As for MOV variants, there is:
MOV r64, imm64
MOV r/m64, imm32

So I guess the error there is about the attempted "MOV r/m64, imm64" that doesn't exist ?

@vicuna
Copy link
Author

vicuna commented Nov 27, 2015

Comment author: @alainfrisch

A simple workaround exists, so no hurry here. Pushing to "later".

@vicuna
Copy link
Author

vicuna commented Nov 28, 2015

Comment author: @xavierleroy

@oandrieu's analysis is spot on: x86-64 has no "move imm64 to mem64" instruction, only "move imm32 to mem64". ocamlopt uses the latter instruction for the Ispecific(Istore_symbol) operation, which initializes a 64-bit memory location with the address of a symbol.

This works only if the symbol is in the low 4 Gb of the addressing space, and the assembler and linker know about this fact.

It is the case under Linux and MacOS X when producing static code (position-dependent and not in a DLL). Clearly it is not the case under Win64: either the symbol is not guaranteed to be in the low 4 Gb, or the assembler and linker don't support relocations of the "low 32 bits of a symbol address" kind.

Solution 1: turn off the recognition of Istore_symbol for Win64. The code to change is in asmcomp/amd64/selection.ml, method select_store.

Solution 2: suppress the Istore_symbol operation entirely. Even under Linux and MacOS X, it is rarely recognized because the default is to produce PIC code. So, it would not be a big loss.

@vicuna
Copy link
Author

vicuna commented Jul 13, 2016

Comment author: @alainfrisch

There is an IMAGE_REL_AMD64_ADDR32 kind of relocation in COFF for x64 processors, although it's hard to tell exactly what it is supposed to do exactly ("The 32-bit VA of the relocation target" -- I guess it means the image loader is supposed to fail if the target is not in the low 4Gb, or perhaps that it would store its low 32 bits). But:

  • The assembler has no way to know that the symbol will indeed be in the low 4 Gb (even if Windows guaranteed that property for static code -- I don't know if this is the case or not).

  • Even it is produced the relocation kind above, flexdll does not support it (on x64, it supports only ADDR64 and REL32, REL32_1, REL32_2, REL32_4, and actually only ADDR64 in its no_rel_relocs mode).

@vicuna
Copy link
Author

vicuna commented Dec 8, 2016

Comment author: @mshinwell

Superceded by #955 where there is also a proposed patch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants