Search code examples
assemblyx86x86-64masm

x64 doesn't seem to accept an entry point in the END directive as x86 does. Was there any specific reason for this change in the syntax?


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.


Solution

  • 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.