我的环境是 x86 Native Tools for VS 2022。 其他地方的情况可能有所不同 x86-64 和 ARM 等平台。
我正在尝试编译生成的程序集列表 由编译器使用如下命令行
cl foo.c /Fa /FAs
。选项 /Fa
表示需要
列表文件,/FAs
表示需要
列表文件中对应的 C 源代码行。
获得列表文件后,我尝试编译 带有命令行的列表文件,例如
ml foo.asm
。我添加了相应的链接选项
就像 /link /subsystem:windows
和 /link User32.lib
。
我在某些文件中成功了,但在以下情况下失败了: 尝试用最小的 Windows API 来做到这一点 消息循环。
该C文件可以编译并运行良好。 然而,当我尝试编译它的列表文件时, 汇编器,
ml
,失败并出现错误:
win.asm(45) : error A2008:syntax error : flat
当我查看第45行时,是:
voltbl SEGMENT
_volmd DD 0ffffffffH
(LINE 45) DDSymXIndex: FLAT:_WinMain@16
DD 0dH
DD 0ecH
voltbl ENDS
我猜是
FLAT
中的DDSymXIndex: FLAT:_WinMain@16
导致了这个问题。
但是,这个列表文件是由
cl
生成的,
编译器本身。因此,不应该有
成为问题。是否有一些命令行选项
我错过了?
有一个相关问题。然而,这个问题 似乎与库链接有关,即 不是我的情况。 链接如下。
这个文件非常简单。 它只包含一个空的主函数, 什么都不做。
#include <windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
}
此文件会弹出一个消息框。 它的程序集列表文件也 编译成功。
我使用了以下命令行 生成列表文件并编译:
> cl /Fa /FAs msgbox.c
> del msgbox.exe (TO MAKE SURE A NEW EXECUTABLE IS CREATED)
> ml msgbox.asm /link User32.lib
(^^^^^^^^^^^^^^^^ THIS PART IS IMPORTANT)
> msgbox
(IT RUNS AND WORKS)
代码:
#include <windows.h>
#pragma comment(lib, "User32.lib")
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
MessageBox(NULL, "TEST", "TITLE",
MB_ICONEXCLAMATION | MB_OK);
}
这是一个有效的C文件,可以编译 由C编译器和生成 可执行文件运行。然而,大会 此 C 文件生成的列表文件 编译失败。参见上文 编译错误的详细信息。
#include <windows.h>
#pragma comment(lib, "User32.lib")
#pragma comment(lib, "Shell32.lib")
#pragma comment(lib, "gdi32.lib")
LRESULT CALLBACK wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
BOOL register_window(const char * szClassName, HINSTANCE hInstance) {
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = wndproc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
wc.lpszMenuName = NULL;
wc.lpszClassName = szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (RegisterClassEx( & wc))
return TRUE;
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return FALSE;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
MSG Msg;
const char szClassName[] = "myWindowClass";
if (!register_window(szClassName, hInstance))
return 0;
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, szClassName, "MY WINDOW",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
640, 480, NULL, NULL,
hInstance, NULL);
if (!hwnd) {
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage( & Msg, NULL, 0, 0) > 0) {
TranslateMessage( & Msg);
DispatchMessage( & Msg);
}
return Msg.wParam;
}
汇编器未能生成 目标文件,在到达之前 链接阶段。 因此,目前还没有必要 检查可能出现的问题 链接阶段。
; Listing generated by Microsoft (R) Optimizing Compiler Version 19.38.33130.0
TITLE C:\...\win.obj
.686P
.XMM
include listing.inc
.model flat
INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES
PUBLIC _WinMain@16
PUBLIC _wndproc@16
PUBLIC _register_window
EXTRN __imp__CreateSolidBrush@4:PROC
EXTRN __imp__GetMessageA@16:PROC
EXTRN __imp__TranslateMessage@4:PROC
EXTRN __imp__DispatchMessageA@4:PROC
EXTRN __imp__DefWindowProcA@16:PROC
EXTRN __imp__PostQuitMessage@4:PROC
EXTRN __imp__RegisterClassExA@4:PROC
EXTRN __imp__CreateWindowExA@48:PROC
EXTRN __imp__DestroyWindow@4:PROC
EXTRN __imp__ShowWindow@8:PROC
EXTRN __imp__UpdateWindow@4:PROC
EXTRN __imp__MessageBoxA@16:PROC
EXTRN __imp__LoadCursorA@8:PROC
EXTRN __imp__LoadIconA@8:PROC
EXTRN @__security_check_cookie@4:PROC
EXTRN ___security_cookie:DWORD
_DATA SEGMENT
$SG72129 DB 'Error!', 00H
ORG $+1
$SG72130 DB 'Window Registration Failed!', 00H
$SG72148 DB 'myWindowClass', 00H
ORG $+2
$SG72150 DB 'MY WINDOW', 00H
ORG $+2
$SG72152 DB 'Error!', 00H
ORG $+1
$SG72153 DB 'Window Creation Failed!', 00H
_DATA ENDS
voltbl SEGMENT
_volmd DD 0ffffffffH
DDSymXIndex: FLAT:_WinMain@16
DD 0dH
DD 0ecH
voltbl ENDS
; Function compile flags: /Odtp
; File C:\...\win.c
_TEXT SEGMENT
_wc$ = -48 ; size = 48
_szClassName$ = 8 ; size = 4
_hInstance$ = 12 ; size = 4
_register_window PROC
; 20 : BOOL register_window(const char * szClassName, HINSTANCE hInstance) {
push ebp
mov ebp, esp
sub esp, 48 ; 00000030H
; 21 : WNDCLASSEX wc;
; 22 : wc.cbSize = sizeof(WNDCLASSEX);
mov DWORD PTR _wc$[ebp], 48 ; 00000030H
; 23 : wc.style = 0;
mov DWORD PTR _wc$[ebp+4], 0
; 24 : wc.lpfnWndProc = wndproc;
mov DWORD PTR _wc$[ebp+8], OFFSET _wndproc@16
; 25 : wc.cbClsExtra = 0;
mov DWORD PTR _wc$[ebp+12], 0
; 26 : wc.cbWndExtra = 0;
mov DWORD PTR _wc$[ebp+16], 0
; 27 : wc.hInstance = hInstance;
mov eax, DWORD PTR _hInstance$[ebp]
mov DWORD PTR _wc$[ebp+20], eax
; 28 : wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
push 32512 ; 00007f00H
push 0
call DWORD PTR __imp__LoadIconA@8
mov DWORD PTR _wc$[ebp+24], eax
; 29 : wc.hCursor = LoadCursor(NULL, IDC_ARROW);
push 32512 ; 00007f00H
push 0
call DWORD PTR __imp__LoadCursorA@8
mov DWORD PTR _wc$[ebp+28], eax
; 30 : wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
push 0
call DWORD PTR __imp__CreateSolidBrush@4
mov DWORD PTR _wc$[ebp+32], eax
; 31 : wc.lpszMenuName = NULL;
mov DWORD PTR _wc$[ebp+36], 0
; 32 : wc.lpszClassName = szClassName;
mov ecx, DWORD PTR _szClassName$[ebp]
mov DWORD PTR _wc$[ebp+40], ecx
; 33 : wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
push 32512 ; 00007f00H
push 0
call DWORD PTR __imp__LoadIconA@8
mov DWORD PTR _wc$[ebp+44], eax
; 34 : if (RegisterClassEx( & wc))
lea edx, DWORD PTR _wc$[ebp]
push edx
call DWORD PTR __imp__RegisterClassExA@4
movzx eax, ax
test eax, eax
je SHORT $LN2@register_w
; 35 : return TRUE;
mov eax, 1
jmp SHORT $LN1@register_w
$LN2@register_w:
; 36 : MessageBox(NULL, "Window Registration Failed!", "Error!",
push 48 ; 00000030H
push OFFSET $SG72129
push OFFSET $SG72130
push 0
call DWORD PTR __imp__MessageBoxA@16
; 37 : MB_ICONEXCLAMATION | MB_OK);
; 38 : return FALSE;
xor eax, eax
$LN1@register_w:
; 39 : }
mov esp, ebp
pop ebp
ret 0
_register_window ENDP
_TEXT ENDS
; Function compile flags: /Odtp
; File C:\...\win.c
_TEXT SEGMENT
tv64 = -4 ; size = 4
_hwnd$ = 8 ; size = 4
_msg$ = 12 ; size = 4
_wParam$ = 16 ; size = 4
_lParam$ = 20 ; size = 4
_wndproc@16 PROC
; 6 : LRESULT CALLBACK wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
push ebp
mov ebp, esp
push ecx
; 7 : switch (msg) {
mov eax, DWORD PTR _msg$[ebp]
mov DWORD PTR tv64[ebp], eax
cmp DWORD PTR tv64[ebp], 2
je SHORT $LN5@wndproc
cmp DWORD PTR tv64[ebp], 16 ; 00000010H
je SHORT $LN4@wndproc
jmp SHORT $LN6@wndproc
$LN4@wndproc:
; 8 : case WM_CLOSE:
; 9 : DestroyWindow(hwnd);
mov ecx, DWORD PTR _hwnd$[ebp]
push ecx
call DWORD PTR __imp__DestroyWindow@4
; 10 : break;
jmp SHORT $LN2@wndproc
$LN5@wndproc:
; 11 : case WM_DESTROY:
; 12 : PostQuitMessage(0);
push 0
call DWORD PTR __imp__PostQuitMessage@4
; 13 : break;
jmp SHORT $LN2@wndproc
$LN6@wndproc:
; 14 : default:
; 15 : return DefWindowProc(hwnd, msg, wParam, lParam);
mov edx, DWORD PTR _lParam$[ebp]
push edx
mov eax, DWORD PTR _wParam$[ebp]
push eax
mov ecx, DWORD PTR _msg$[ebp]
push ecx
mov edx, DWORD PTR _hwnd$[ebp]
push edx
call DWORD PTR __imp__DefWindowProcA@16
jmp SHORT $LN1@wndproc
$LN2@wndproc:
; 16 : }
; 17 : return 0;
xor eax, eax
$LN1@wndproc:
; 18 : }
mov esp, ebp
pop ebp
ret 16 ; 00000010H
_wndproc@16 ENDP
_TEXT ENDS
; Function compile flags: /Odtp
; File C:\...\win.c
_TEXT SEGMENT
_Msg$ = -52 ; size = 28
_hwnd$ = -24 ; size = 4
_szClassName$ = -20 ; size = 14
__$ArrayPad$ = -4 ; size = 4
_hInstance$ = 8 ; size = 4
_hPrevInstance$ = 12 ; size = 4
_lpCmdLine$ = 16 ; size = 4
_nCmdShow$ = 20 ; size = 4
_WinMain@16 PROC
; 43 : {
push ebp
mov ebp, esp
sub esp, 52 ; 00000034H
mov eax, DWORD PTR ___security_cookie
xor eax, ebp
mov DWORD PTR __$ArrayPad$[ebp], eax
; 44 : HWND hwnd;
; 45 : MSG Msg;
; 46 : const char szClassName[] = "myWindowClass";
mov eax, DWORD PTR $SG72148
mov DWORD PTR _szClassName$[ebp], eax
mov ecx, DWORD PTR $SG72148+4
mov DWORD PTR _szClassName$[ebp+4], ecx
mov edx, DWORD PTR $SG72148+8
mov DWORD PTR _szClassName$[ebp+8], edx
mov ax, WORD PTR $SG72148+12
mov WORD PTR _szClassName$[ebp+12], ax
; 47 :
; 48 : if (!register_window(szClassName, hInstance))
mov ecx, DWORD PTR _hInstance$[ebp]
push ecx
lea edx, DWORD PTR _szClassName$[ebp]
push edx
call _register_window
add esp, 8
test eax, eax
jne SHORT $LN4@WinMain
; 49 : return 0;
xor eax, eax
jmp $LN1@WinMain
$LN4@WinMain:
; 50 :
; 51 : hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, szClassName, "MY WINDOW",
push 0
mov eax, DWORD PTR _hInstance$[ebp]
push eax
push 0
push 0
push 480 ; 000001e0H
push 640 ; 00000280H
push -2147483648 ; 80000000H
push -2147483648 ; 80000000H
push 13565952 ; 00cf0000H
push OFFSET $SG72150
lea ecx, DWORD PTR _szClassName$[ebp]
push ecx
push 512 ; 00000200H
call DWORD PTR __imp__CreateWindowExA@48
mov DWORD PTR _hwnd$[ebp], eax
; 52 : WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
; 53 : 640, 480, NULL, NULL,
; 54 : hInstance, NULL);
; 55 :
; 56 : if (!hwnd) {
cmp DWORD PTR _hwnd$[ebp], 0
jne SHORT $LN5@WinMain
; 57 : MessageBox(NULL, "Window Creation Failed!", "Error!",
push 48 ; 00000030H
push OFFSET $SG72152
push OFFSET $SG72153
push 0
call DWORD PTR __imp__MessageBoxA@16
; 58 : MB_ICONEXCLAMATION | MB_OK);
; 59 : return 0;
xor eax, eax
jmp SHORT $LN1@WinMain
$LN5@WinMain:
; 60 : }
; 61 :
; 62 : ShowWindow(hwnd, nCmdShow);
mov edx, DWORD PTR _nCmdShow$[ebp]
push edx
mov eax, DWORD PTR _hwnd$[ebp]
push eax
call DWORD PTR __imp__ShowWindow@8
; 63 : UpdateWindow(hwnd);
mov ecx, DWORD PTR _hwnd$[ebp]
push ecx
call DWORD PTR __imp__UpdateWindow@4
$LN2@WinMain:
; 64 :
; 65 : while (GetMessage( & Msg, NULL, 0, 0) > 0) {
push 0
push 0
push 0
lea edx, DWORD PTR _Msg$[ebp]
push edx
call DWORD PTR __imp__GetMessageA@16
test eax, eax
jle SHORT $LN3@WinMain
; 66 : TranslateMessage( & Msg);
lea eax, DWORD PTR _Msg$[ebp]
push eax
call DWORD PTR __imp__TranslateMessage@4
; 67 : DispatchMessage( & Msg);
lea ecx, DWORD PTR _Msg$[ebp]
push ecx
call DWORD PTR __imp__DispatchMessageA@4
; 68 : }
jmp SHORT $LN2@WinMain
$LN3@WinMain:
; 69 : return Msg.wParam;
mov eax, DWORD PTR _Msg$[ebp+8]
$LN1@WinMain:
; 70 : }
mov ecx, DWORD PTR __$ArrayPad$[ebp]
xor ecx, ebp
call @__security_check_cookie@4
mov esp, ebp
pop ebp
ret 16 ; 00000010H
_WinMain@16 ENDP
_TEXT ENDS
END
总结一下:
cl
生成。就是这些行:
voltbl SEGMENT
_volmd DD 0ffffffffH
(LINE 45) DDSymXIndex: FLAT:_WinMain@16
DD 0dH
DD 0ecH
voltbl ENDS
通过删除这些行,程序集列表 只需编译并运行即可。
DDSym
可能类似于“调试符号”?
因此我尝试删除这些行,并且
它只是有效。
但是我还是不明白为什么C编译器 生成这些无法编译的行 汇编器。也许我错过了一些 命令行选项 告诉汇编器如何处理这些调试 符号。无论如何,我目前不会研究它。