Skip to content

State Error LNK2001 unresolved external symbol _mainCRTStartup #16

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

Open
FashionFlora opened this issue May 4, 2021 · 5 comments
Open

Comments

@FashionFlora
Copy link

image
Whats wrong?

@Zman2024
Copy link

Zman2024 commented Feb 6, 2022

I'm assuming that you're trying to write just assembly and nothing else, but it's in a C++ project. Under the hood in C++ int main is not the first thing that is called when your program starts, there is setup required for the C runtime to work correctly and the setup function for that (_mainCRTSetup) is generated by the compiler. If all you want is to run assembly while being able to get CRT functions (like malloc) I'd suggest just defining something like extern "C" int asmMain() in a C++ file and call it from C++ like so:

#include <iostream>

extern "C" int asmMain();

// _mainCRTSetup secretly called before this
int main()
{
    return asmMain();
}

and in assembly your main function is now called asmMain which will run after _mainCRTSetup so something like this in assembly:

bits 64
global asmMain

asmMain:
    mov rax, 69 ; some return code, 0 if no error but 69 is funny
    ret  

hope this was helpful, but this issue is pretty old so I'm sure you've figured it out yourself by now

@GWOSTIK
Copy link

GWOSTIK commented Feb 8, 2023

@Zman2024 Tried your simple application, but having the same issue.

image

main.cpp

extern "C" int asmMain();

int main()
{
	return asmMain();
}

asmmain.asm

[BITS 64]

GLOBAL asmMain

asmMain:
    mov rax, 69
    ret  

Any ideas what could be wrong?

@Zman2024
Copy link

Zman2024 commented Feb 8, 2023

@Zman2024 Tried your simple application, but having the same issue.

image

main.cpp

extern "C" int asmMain();

int main()
{
	return asmMain();
}

asmmain.asm

[BITS 64]

GLOBAL asmMain

asmMain:
    mov rax, 69
    ret  

Any ideas what could be wrong?

it seems like your main.cpp and asmmain.asm object files aren't linking to each other for some reason

@brettrjones-github
Copy link

I ran into a similar issue. everything looked correct with dumpbin -symbols .\assemblyNasm64.obj
but could not get it to link in visual studio 2019
I changed
global get_assembly_test_num ; makes this visible to linker

get_assembly_test_num:
mov rax,1234 ; just return a constant
ret
to
section .text ; required or visual studio will not link the function

global get_assembly_test_num ; makes this visible to linker

get_assembly_test_num:
mov rax,1234 ; just return a constant
ret

and then it linked
you must give it a section or it will not link in visual studio
Also note. if win32 the function requires a leading _ whereas win64 does not

@GerHobbelt
Copy link
Contributor

FYI:

  • quoting https://forum.nasm.us/index.php?topic=3879.0 (emphasis mine):

    NASM (and other assemblers) usually have directives to organize you code in sections. These sections can be viewed as "segments" in real mode, but they are only a way to organize code.

    Your operating system loads an executable in blocks. There is an executable block (.text), data blocks (.data, .rodata, .bss), and more. The keyword section tells the assembler what attributes these sections have - In systems like Windows and Unixes, the sections starting with a single dot are system sections with default attributes. You can create your own. In the old MSDOS, this dot is substituted by an underscore, like _TEXT, _DATA and _BSS (and, for some linkers you must tell the actual class: _TEXT has class CODE).

    In a Master boot record, for example, you don't need sections. A single sector is loaded from disk via interrupt 0x19 at the segment 0, offset 0x7c00 (this is STANDARD), with CS=DS=ES=0 (why? Because BIOS Data area starts at segment 0x40, and can be accessed via offset 0x4xx, at segment 0). You can code your MBR not using sections (because you are not creating an EXE file!).

    TL;DR / rephrased: As you're creating Windows .exe files and the regular linker is involved, that one expects functions to sit in a 'section .code'.

    That's a bit of a white lie as your CAN use other sections, but that will very probably also involve specific __declspec() tweaks in other source files. That's advanced hackery and not useful for the usual stuff.

If you want to go down the rabbit hole, here's one starting point: https://learn.microsoft.com/en-us/cpp/cpp/code-seg-declspec?view=msvc-170 : __declspec(code_seg ...)

For us normies, who don't need that deep-geek stuff, it's the set section .code, section .data, section .bss in our ASM source files and that should cover our bases pretty neatly. 😉

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

No branches or pull requests

5 participants