Не удалось скомпилировать точный листинг сборки, созданный компилятором

Моя среда — это собственные инструменты x86 для VS 2022. В других странах ситуация может быть иной платформы, такие как x86-64 и ARM.

Я пытаюсь скомпилировать созданные списки сборок компилятором с помощью командных строк, таких как cl foo.c /Fa /FAs. Опция /Fa означает требование файл листинга, а /FAs означает требование соответствующие строки исходного кода C в файле листинга.

Получив файл листинга, я попытался скомпилировать файл листинга с командной строкой типа ml foo.asm. Я добавил соответствующие варианты ссылок например /link /subsystem:windows и /link User32.lib.

Мне удалось создать некоторые файлы, но не удалось, когда пытаюсь сделать это с минимальным API Windows цикл сообщений.

Этот файл 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, сам компилятор. Следовательно, не следует быть проблемы. Есть ли какие-нибудь параметры командной строки Я пропустил?

Есть связанный с этим вопрос. Однако этот вопрос похоже, речь идет о связывании библиотеки, что не мой случай. Ссылка ниже.

Скомпилировать выходные данные сборки, сгенерированные VC++?

Приложение 1: Файл, файлы листинга которого успешно скомпилированы.

Этот файл очень простой. Он содержит только пустую основную функцию, ничего не делать.

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
}

Приложение 2: Еще один файл, файлы листинга которого успешно скомпилированы.

Этот файл вызывает окно сообщения. Его файл листинга сборки также успешно компилируется.

Я использовал следующие командные строки чтобы сгенерировать файл листинга и скомпилировать:

> 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);
}

Приложение 3: Исходный код C минимального файла цикла сообщений Windows API, файл листинга которого не удалось скомпилировать.

Это действительный файл 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;
}

Приложение 4: Полный файл листинга, который не удалось скомпилировать.

Ассемблеру не удалось сгенерировать объектный файл, прежде чем достичь этап связывания. Поэтому на данный момент это ненужно чтобы проверить возможные проблемы в этап связывания.

; 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

Обернуть:

  1. Я пытаюсь скомпилировать листинг сборки создано cl.
  2. Мне удалось создать два крошечных тестовых файла.
  3. Хотя я использую тот же метод, Мне не удалось выполнить другой тестовый файл.
EXTRN __imp__xxx:DWORD должно быть, а не PROC (в x64 QWORD)
RbMm 29.07.2024 00:36
__imp__xxx это переменная размера указателя, которая содержит адрес импортируемой функции. и вам не нужно также call DWORD PTR __imp__xxx делать. просто call __imp__xxx
RbMm 29.07.2024 02:57

@RbMm Спасибо, я тоже этого не знал. Это также было бы полезно, поскольку CALL используется очень часто.

Limina102 29.07.2024 05:11
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
58
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Именно эти строки и вызвали проблему:

           voltbl   SEGMENT
           _volmd   DD  0ffffffffH
(LINE 45)           DDSymXIndex:    FLAT:_WinMain@16
                    DD  0dH
                    DD  0ecH
           voltbl   ENDS

Удалив эти строки, листинг сборки просто компилируется и работает:

>ml win.asm /link User32.lib Shell32.lib GDI32.lib
Microsoft (R) Macro Assembler Version 14.38.33130.0
Copyright (C) Microsoft Corporation.  All rights reserved.

 Assembling: win.asm
Microsoft (R) Incremental Linker Version 14.38.33130.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/OUT:win.exe
win.obj
User32.lib
Shell32.lib
GDI32.lib

DDSym может быть что-то вроде «Символ отладки». Поэтому я попытался удалить эти строки и это просто работает.

Но я до сих пор не понимаю, почему компилятор C генерирует эти строки, которые не могут быть скомпилированы с помощью ассемблер. Возможно, я что-то пропустил параметры командной строки сообщить ассемблеру, как обрабатывать эту отладку символы. В любом случае я не буду сейчас этим заниматься.

Вывод сборки MSVC представляет собой «листинг», который, как я слышал, не предназначен для фактической сборки для создания пригодного для использования объектного файла. Иногда это происходит потому, что он включает ненужные функции, но я думаю, это может быть еще одним примером. GCC и clang -S создают исходный файл asm, который будет собран в тот же объектный файл, который они создали бы с помощью -c вместо -S.

Peter Cordes 29.07.2024 20:11

@PeterCordes Спасибо, я этого не знал. Таким образом, я бы обратился к GCC и clang, чтобы получить исходный код сборки, который можно напрямую скомпилировать.

Limina102 30.07.2024 03:36

Другие вопросы по теме

Похожие вопросы

Окно не получает фокус даже при перемещении вверх
После перемещения файла в другое место и последующего создания файла с тем же именем в исходном месте время создания неверно
Java Graphics2D.drawImage() отображает размытое изображение только в Windows с масштабированием 125% и только в версиях Java после Java 8
Кто-нибудь знает, почему моя переменная (x) изменила свое значение с 3 на 0 (1 после x++) в этой программе? Я пытаюсь создать систему регистрации, но она перезаписывает
Как я могу установить текстовое значение в соответствии с позицией
Можно ли определить функцию C++, в которой один параметр передается через регистр EAX?
Получение имени пользователя Windows в формате «Имя Фамилия», когда пользователь является частью группы
Мой чат-сервер Python не отправляет сообщения должным образом
Собственный диалог открытия файла в Windows Ruby
Пытаюсь запустить сервер Minecraft и постоянно получаю сообщение об ошибке: невозможно получить доступ к jarfile