编译汇编代码时出现undefined reference to `WinMain@16'错误求助
解决MinGW下汇编代码链接报错
undefined reference to 'WinMain@16'的问题 问题描述
我通过GCC的-S选项将自行编写的C语言快速排序函数编译为汇编代码,编译该汇编代码时GCC报错:undefined reference to 'WinMain@16'。我对汇编完全不了解,怀疑该问题与操作系统相关。另外,手动编译项目时无报错,但通过CMake构建时出现该错误,相关代码及环境信息如下:
汇编代码
.file "quickSort.c" .text .globl _partition .def _partition; .scl 2; .type 32; .endef _partition: LFB0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 subl $16, %esp movl 16(%ebp), %eax leal 0(,%eax,4), %edx movl 8(%ebp), %eax addl %edx, %eax movl (%eax), %eax movl %eax, -12(%ebp) movl 12(%ebp), %eax movl %eax, -4(%ebp) movl 12(%ebp), %eax movl %eax, -8(%ebp) jmp L2 L4: movl -8(%ebp), %eax leal 0(,%eax,4), %edx movl 8(%ebp), %eax addl %edx, %eax movl (%eax), %eax cmpl %eax, -12(%ebp) jl L3 movl -8(%ebp), %eax leal 0(,%eax,4), %edx movl 8(%ebp), %eax addl %edx, %eax movl (%eax), %eax movl %eax, -16(%ebp) movl -4(%ebp), %eax leal 0(,%eax,4), %edx movl 8(%ebp), %eax addl %edx, %eax movl -8(%ebp), %edx leal 0(,%edx,4), %ecx movl 8(%ebp), %edx addl %ecx, %edx movl (%eax), %eax movl %eax, (%edx) movl -4(%ebp), %eax leal 0(,%eax,4), %edx movl 8(%ebp), %eax addl %eax, %edx movl -16(%ebp), %eax movl %eax, (%edx) addl $1, -4(%ebp) L3: addl $1, -8(%ebp) L2: movl -8(%ebp), %eax cmpl 16(%ebp), %eax jl L4 movl -4(%ebp), %eax leal 0(,%eax,4), %edx movl 8(%ebp), %eax addl %edx, %eax movl 16(%ebp), %edx leal 0(,%edx,4), %ecx movl 8(%ebp), %edx addl %ecx, %edx movl (%eax), %eax movl %eax, (%edx) movl -4(%ebp), %eax leal 0(,%eax,4), %edx movl 8(%ebp), %eax addl %eax, %edx movl -12(%ebp), %eax movl %eax, (%edx) movl -4(%ebp), %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc LFE0: .globl _quick_sort .def _quick_sort; .scl 2; .type 32; .endef _quick_sort: LFB1: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 subl $40, %esp movl 12(%ebp), %eax cmpl 16(%ebp), %eax jge L9 movl 16(%ebp), %eax movl %eax, 8(%esp) movl 12(%ebp), %eax movl %eax, 4(%esp) movl 8(%ebp), %eax movl %eax, (%esp) call _partition movl %eax, -12(%ebp) movl -12(%ebp), %eax subl $1, %eax movl %eax, 8(%esp) movl 12(%ebp), %eax movl %eax, 4(%esp) movl 8(%ebp), %eax movl %eax, (%esp) call _quick_sort movl -12(%ebp), %eax leal 1(%eax), %edx movl 16(%ebp), %eax movl %eax, 8(%esp) movl %edx, 4(%esp) movl 8(%ebp), %eax movl %eax, (%esp) call _quick_sort jmp L6 L9: nop L6: leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc LFE1: .ident "GCC: (MinGW.org GCC Build-2) 9.2.0"
C语言代码
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <limits.h> #define LN 100 #define ERROR(...) (printf(__VA_ARGS__)) extern void quick_sort(int *array, int x, int y); // here is the rest of the code int main(int argc, char *argv[]) { int left_border = INT_MIN, right_border = INT_MAX; int return_code = read_border(argv, argc, &left_border, &right_border); if (return_code != 0) { printf("%d\n", return_code); return return_code; } int array[LN] = {0}, stdout_array[LN] = {0}, stderr_array[LN] = {0}; int count_elements = read_array(array, stdout_array, stderr_array, left_border, right_border); int sorted_array[LN] = {0}; _memccpy(sorted_array, array, array[count_elements-1] - '0', count_elements * sizeof(int)); quick_sort(sorted_array, 0, count_elements-1); int answer = count_sorted_elements(array, sorted_array, count_elements); print_stdout_or_stderr(stdout_array, stderr_array, array[0]); printf("%d", answer); return answer; }
CMakeLists.txt
file(GLOB_RECURSE C_SOURCES ./*.c) file(GLOB_RECURSE ASM_SOURCES ./*.s) add_executable(main ${C_SOURCES} ${ASM_SOURCES}) if(MSVC) target_compile_options(main PRIVATE /W4 /WX) else() target_compile_options(main PRIVATE -Wall -Wextra -pedantic -Werror) endif()
GCC版本
MinGW.org GCC Build-2 9.2.0
解决建议
1. 修复CMake的文件匹配逻辑
file(GLOB_RECURSE)的匹配规则容易引入冗余文件:
- 如果原
quickSort.c还在目录中,CMake会同时编译C版和汇编版的快速排序函数,导致符号冲突,链接器无法识别正确的main入口。 - 也可能出现带有
main函数的C文件未被正确匹配的情况。
解决方法:
- 移除目录中的
quickSort.c,避免重复编译; - 替换
GLOB_RECURSE为明确的文件名列表,例如:set(C_SOURCES main.c) # 替换为你的main函数所在文件名 set(ASM_SOURCES quickSort.s) - 可以在CMakeLists.txt中添加调试语句,确认文件是否被正确识别:
message("C_SOURCES: ${C_SOURCES}") message("ASM_SOURCES: ${ASM_SOURCES}")
2. 明确指定项目为C语言编译
如果CMake默认按C模式编译,会导致函数符号修饰规则变化(C会给函数名添加额外修饰),进而出现入口函数找不到的问题。
解决方法:
在CMakeLists.txt开头添加:
project(MyProject C) set(CMAKE_C_STANDARD 99)
强制项目按C语言标准编译,确保汇编代码中的_quick_sort、_partition符号与C代码中的声明匹配。
3. 理解WinMain@16错误的本质
Windows平台下,链接器默认:
- 控制台程序的入口是
main函数; - GUI程序的入口是
WinMain函数。
当链接器找不到main函数时,会尝试寻找WinMain,找不到就抛出该错误。你的手动编译正常,说明手动命令正确包含了main所在文件和汇编文件,而CMake构建时大概率漏掉了main文件或出现符号冲突。
4. 对比手动编译与CMake的编译命令
通过查看CMake实际执行的编译链接命令,定位差异:
- 如果使用Makefile生成器,执行:
make VERBOSE=1 - 如果使用Ninja生成器,执行:
ninja -v
将输出的命令与你的手动编译命令(例如gcc main.c quickSort.s -o main)对比,检查是否缺少文件、链接选项错误等问题。
内容的提问来源于stack exchange,提问作者just_name
相关产品推荐
相关产品推荐

