2

According to MS documentation it appears that x86 and x64 assemblies have the same syntax as regards the END directive, i.e., that both accept an optionally entry point [address] with this directive. But given this issue in GitHub, it seems that x64 doesn't accept this option. The example below shows this:

EXTERN ExitProcess:PROC
.CODE
main PROC
    mov eax, 10
exit:
    xor ecx, ecx
    call ExitProcess
main ENDP
END main

which produces the following error messages in VS2017:

error A2008: syntax error : main
error A2088: END directive required at end of file

IMHO these error messages are very confusing, specially the second one, which seems to say that there is no END directive in the code.

But assuming that the issue in GitHub is correct, I would like to know whether there was any specific reason for this change in the syntax, from x86 to x64.

Alexander
  • 2,581
  • 11
  • 17
  • 2
    You're asking about MASM, I think? Other assemblers use different syntax. Anyway, put a [mcve] of your 64-bit code in your question directly, as well as a link to external discussion. – Peter Cordes Nov 23 '19 at 09:30
  • @PeterCordes See my edit above. – Alexander Nov 23 '19 at 12:55
  • Do you have spaces or newlines after the `END` directive? Also try to remove the `PROC` and `ENDP` directives and make `main:` a simple label, because the PROC - ENDP may be considered a closed block by the MASM assembler. – zx485 Nov 23 '19 at 12:57
  • @zx485 Other than the string of characters " main" no. – Alexander Nov 23 '19 at 13:01
  • Then try the second part of my comment: replacing PROC - ENDP by a simple label `main:` instead of `main PROC` and `main ENDP`. – zx485 Nov 23 '19 at 13:02
  • @zx485 If I understood you correctly that's what I did: `EXTERN ExitProcess:PROC` `.CODE` `main: ;PROC` `mov eax, 10` `exit:` `xor ecx, ecx` `call ExitProcess` `;main ENDP` `END main` and the errors were the same as before. – Alexander Nov 23 '19 at 13:05
  • Sorry, but then I'm nearly out of suggestions. Maybe check for a [BOM](https://en.wikipedia.org/wiki/Byte_order_mark) at the beginning of the file with a HEX editor... or something. A BOM is usually indicated by the HEX values `FF FE` or similar at the beginning of the file - which will mess everything up. – zx485 Nov 23 '19 at 13:13
  • @zx485 There is no BOM at the beginning of the source file `Project3.asm`. – Alexander Nov 23 '19 at 13:34
  • 1
    Yes, ML64 expects the entry point at the linker options while ML32 expects it as addendum to the END directive. Please take a look to my howto: https://stackoverflow.com/a/52803496/3512216 – rkhb Nov 23 '19 at 14:53
  • 1
    @rkhb You can also pass the entry point as a command line option to the linker with the 32-bit x86 version of MASM as well. In fact, that's how `END start` is implemented, the assembler passes the option `/ENTRY:start` to the linker by putting it in a `.drectve` section of the generated object file. – Ross Ridge Nov 23 '19 at 17:51

1 Answers1

3

This is unfortunately undocumented behaviour for the x64 version of MASM. On this version of the assembler the END directive doesn't accept an entry point symbol. You must simply end your source with a bare "END" statement. (Making the END directive completely useless, as it hasn't been needed to mark the end of the file since MS-DOS 2.0.)

As a workaround, you can specify the entry point with the /ENTRY linker option, which you can set from the Visual Studio IDE under the project's Property Page -> Linker -> Advanced -> Entry Point. You could also rename your entry point to rely on the linker's default entry point, which depends on the subsystem used, as Microsoft's documentation for /ENTRY states:

By default, the starting address is a function name from the C run-time library. The linker selects it according to the attributes of the program, as shown in the following table.
Function name                                 Default for 

mainCRTStartup (or wmainCRTStartup)           An application that uses /SUBSYSTEM:CONSOLE;
                                              calls main (or wmain) 
WinMainCRTStartup (or wWinMainCRTStartup)     An application that uses /SUBSYSTEM:WINDOWS; 
                                              calls WinMain (or wWinMain), which must be
                                              defined to use __stdcall 
_DllMainCRTStartup                            A DLL; calls DllMain if it exists, which must
                                              be defined to use __stdcall 
If the /DLL or /SUBSYSTEM option is not specified, the linker selects a subsystem and entry point depending on whether main or WinMain is defined.

If you really want to specify the entry point in the assembly file itself, then you can use the same method the 32-bit x86 version of MASM uses to inform the linker: put a "/ENTRY" option in the .drectve section. Something like this:

_DRECTVE SEGMENT INFO ALIAS(".drectve")
    DB  " /ENTRY:main "
_DRECTVE ENDS

Note the spaces around the option.

Ross Ridge
  • 38,414
  • 7
  • 81
  • 112
  • What you said is valid only for Debug configurations. In a Release configuration one has to define Properties > Linker > Advanced > Entry Point. There is no default starting address. IMHO this is messy. That's why I'm trying to get some explanation about the different syntax from x86 to x64 and now, about the different behaviors, between a debug and a release configuration, in x64. – Alexander Nov 23 '19 at 19:37
  • @Alexander No, the Microsoft documentation I quoted is correct. – Ross Ridge Nov 23 '19 at 19:39
  • Well, it is not working for me when I select a Release configuration. I'm getting `error LNK2001: unresolved external symbol mainCRTStartup`. – Alexander Nov 23 '19 at 19:41
  • @Alexander Yes, and that shows that documentation is correct, it's using `mainCRTStartup` as the default entry point as the documentation says it would. – Ross Ridge Nov 23 '19 at 19:44
  • Under the column heading "Default for" you wrote: An application that uses /SUBSYSTEM :CONSOLE; calls main or wmain. But it's not calling main in a release configuration, as it does in a Debug configuration. – Alexander Nov 23 '19 at 19:56
  • @Alexander You've read that wrong, and I didn't write that. I copied it verbatim from the Microsoft documentation. It's saying if an application uses /SUBSYSTEM:CONSOLE **or if the application calls main or wmain** then the default entry symbol is "`mainCRTStartup` (or `wmainCRTStartup`)" – Ross Ridge Nov 23 '19 at 20:01
  • When I say you wrote I mean you copied as, we are talking about the text in quoted format above, i.e., the text highlighted with yellow. Nevertheless, I am observing a different behavior between a Debug and a Release configuration that is not explained by the text you copied from MS docs above. – Alexander Nov 23 '19 at 20:12
  • I have probably made some mistake while applying the changes between the debug and release configurations. After further analysis, I'm now verifying that there is no discrepancy between the two configurations. Sorry for the confusion. – Alexander Nov 23 '19 at 20:42