2

I am working on reworking an old masm program to true 64-bit x64 mode using Microsoft's ml64 and link on Windows 10. The linker gives an error in code that has a REX.W prefix.

The linker's /LARGEADDRESSAWARE option sounds like the right thing for full 64 bit support, but it complains. /LARADDRESSAWARE:NO works, but from documentation I have read it seems to be an option for 32-bit programs to go beyond 2GB to maybe 3GB in "compatability mode" maybe. The MS documentation was not clear on this.

I also considered that .data and .code might be the wrong things to use because the MS ml64 documentation says that it is for 32-bit code but doesn't say how to proceed with 64-bit code. But I cannot seem to find a way to not use .data and .code and make things work. Anyway, I don't want to be limited to 4GB by missing some option in link or ml64. I have trimmed the problem down to the simplest example. The following assembles and links:

rem call "vcvars64.bat" or "vcvarsall.bat amd64" first (wherever either is located on your system)
rem using Microsoft (R) Macro Assembler (x64) Version 14.27.29112.0
    ml64 /Fl /c test.asm
rem using Microsoft (R) Incremental Linker Version 14.27.29112.0
 
rem The following works but does this really build a full over 4gb capable 64-bit executable?
rem link /entry:main /machine:x64 /LARGEADDRESSAWARE:NO test.obj  

rem The following gives a link error: "test.obj : error LNK2017: 'ADDR32' relocation to 'text' invalid without /LARGEADDRESSAWARE:NO"
    link /entry:main /machine:x64 /LARGEADDRESSAWARE test.obj     

    test.exe

The following is the test.asm program:

   .data

text    db 'xHello 64', 0

   .code

main proc

   mov rsi,1
   lea r8,[text+rsi] ; link complains with this version
;  lea r8,[text+1]   ; this works  

   ret ; I know windows should use ExitProcess but was avoiding library issues to simplify this example
main endp

   end
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Vikors
  • 21
  • 1
  • 1
    The key point is that the only RIP-relative addressing mode is `[rel32]`. MASM syntax hides the difference, but `[Text + rsi]` can only use `[absolute_disp32 + reg]`. See [Can rip be used with another register with RIP-relative addressing?](https://stackoverflow.com/q/48124293) / [How do RIP-relative variable references like "\[RIP + \_a\]" in x86-64 GAS Intel-syntax work?](https://stackoverflow.com/q/54745872) – Peter Cordes Mar 05 '22 at 14:41
  • Does this answer your question? [Can rip be used with another register with RIP-relative addressing?](https://stackoverflow.com/questions/48124293/can-rip-be-used-with-another-register-with-rip-relative-addressing) (dammit, edited tags before trying to close, so none of my gold badges applied.) – Peter Cordes Mar 05 '22 at 14:41

1 Answers1

0

Load Effective Address syntax is

[base+(index*scale)+disp]

base = register 
index = register 
scale = 1,2,4,8 
displacement = 8, 16 or 32-bit value.

'ADDR32' relocation happens when using a 64bit address as an offset. To fix, try putting the address of Text into a register first. For example

lea             r9,Text
lea             r8,[r9+rsi]
vengy
  • 1,548
  • 10
  • 18
  • 1
    That still gives me the same link error when specifying /LARGEADDRESSAWARE. Without /LARGEADDRESSAWARE, am I getting a true 64-bit code executable capable of going beyond 4GB of memory because it acts the same as if I specified /LARGEADDRESSAWARE:NO? – Vikors Nov 12 '21 at 04:43
  • Yes. No need for that option under windows 64-bit. The virtual address space for 64-bit programs is 256 TB. – vengy Nov 12 '21 at 12:03
  • Yes, but 64-bit programs that aren't LARGEADDRESSAWARE only use the low 2GiB of virtual address space, at least for static code/data. So they can use 32-bit absolute addresses in their machine code, with ASLR applying fixups. – Peter Cordes Mar 05 '22 at 14:45
  • 1
    *using a 64bit address as an offset* is what `[Text]` is doing: the symbol is the offset part of the seg:off, i.e. the effect address. The problem is using it *with a register*, because the only RIP-relative addressing mode is `[rel32]`, separate from the [base + idx*scale + disp0/8/32]` case, so quoting that doesn't explain it. (But I think that's what you're trying to explain, using offset as a synonym for displacement, instead of its meaning in x86-64 technical terminology). – Peter Cordes Mar 05 '22 at 14:50
  • 1
    It would also be a problem to use `mov r9d, OFFSET Text`, but `mov r9, OFFSET Text` would use an absolute 64-bit address (which is less efficient than RIP-relative LEA). – Peter Cordes Mar 05 '22 at 14:50