ld: Linken mit User32.dll



  • Hallo,
    ich habe in Assembler ein kleines Programm geschrieben, das laut den Beschreibungen von MSDN ausschließlich Funktionen aus User32.dll nutzt.

    Der Assembler erzeugt, wie erwartet, eine Objektdatei. Jetzt will ich die Objektdatei mit dem ld linken, und zwar mit User32.dll.

    Ich habe diese Datei im Explorer gesucht und festgestellt, dass die einzige Datei unter diesem Namen im Ordner
    C:\Windows\System32
    zu finden ist.

    Ich rufe ld mit folgenden Parametern auf:
    ld input.o -LC:\Windows\System32 -lUser32

    Der ld gibt allerdings trotzdem Fehlermeldungen aus: "undefined references to ..."

    Ich habe in der Assemblerdatei die externen Funktionen mittels ".extern" kenntlich gemacht, also
    .extern FunktionsName

    1. Ist das so ok, oder muss es heißen:
    .extern _FunktionsName

    2. Ich habe beide Schreibweisen ausprobiert, beidemale gibt ld diese Fehlermeldungen.

    3. Wo liegt nun das Problem?



  • Was für einen Assembler benutzt du? Warum benutzt du nicht Link.exe?

    z.B. mit NASM und Link.exe wäre folgendes möglich:

    nasm -fwin32 hello.asm
    link /subsystem:console /nodefaultlib /entry:main hello.obj
    

    Was für undefined references werden denn gelistet? Sicher, dass die nicht aus kernel32 kommen und du das auch mitlinken musst?



  • Ich genutze den as und den ld .

    ... und ich habe keine Ahnung, was "Link.exe" ist.

    Laut MSDN ist die Funktion aus windows.h, und in der Library User32.lib, als DLL User32.dll.



  • Achso, du benutzt die GNU Tools. In Cygwin?

    Wie geschrieben würde mich immernoch interessieren, welche Referenzen nicht gefunden werden.



  • Nicht Cygwin, sondern Mingw.

    Ich nutze in meinem kleinen Programm genau 3 Funktionen, alle sind aus User32.dll, und bei allen dreien werden Fehlermeldungen ausgegeben.

    Ich vermute eher, dass ich die Funktionen mit ".extern" nicht richtig angebe.
    Wie gesagt, ich verstehe nicht, ob man die Funktionen einfach unter ihrem Funktionsnamen, wie er eben in windows.h steht, oder mit "_Funktionsname" angeben soll.



  • Eigentlich musst du die User32-Lib von MinGW linken und nicht die aus C:\Windows. Die sollte unter C:\MinGW\lib liegen (libuser32.a oder ähnlich).

    Wegen den Funktionen: Benutzt du das Include user32.inc?

    Kannst du vielleicht einen Beispielcode posten?

    Hier ist ein Beispiel mit MsgBox und ExitProcess (letzteres benötigt kernel32): http://www.asmcommunity.net/forums/topic/?id=29731
    Vielleicht hilft dir das weiter.



  • oenone schrieb:

    Eigentlich musst du die User32-Lib von MinGW linken und nicht die aus C:\Windows. Die sollte unter C:\MinGW\lib liegen (libuser32.a oder ähnlich).

    Die Datei ist da, aber wie linke ich sie?

    -llibuser32 funktioniert nicht, -luser32 auch nicht.

    Und mingw hat keine user32.inc, deshalb muss ich ja die benötigten Funktionen selbst als extern deklarieren.



  • Assembler-Lerner schrieb:

    Die Datei ist da, aber wie linke ich sie?

    -llibuser32 funktioniert nicht, -luser32 auch nicht.

    Eigentlich genauso wie du es ursprünglich versucht hast: -LC:\MinGW\lib -lUser32

    Assembler-Lerner schrieb:

    Und mingw hat keine user32.inc, deshalb muss ich ja die benötigten Funktionen selbst als extern deklarieren.

    Die meisten C-Compiler fügen den _ an. Das dürfte bei den Win32-Funktionen auch der Fall sein, also musst du .extern _FunktionsName benutzen.



  • Leider besteht das Problem weiterhin.



  • Ohne Quellcode kann ich dir glaube ich nicht weiterhelfen.

    Ich hab es aber auch mal ausprobiert:

    hello.asm:

    .extern _MessageBoxA@16
    .extern _ExitProcess@4
    
    .section .data
        window_title:
            .ascii "Message box\0"
        window_message:
            .ascii "It works!!!\0"
    
    .section .text
        .globl _start
        _start:
    
            # displays a message box       
            push    $0x0
            push    $window_title
            push    $window_message
            push    $0x0
            call    _MessageBoxA@16
            movl    $0x0, %eax
    
            # exit
            push    $0x0
            call    _ExitProcess@4
    

    Dann assemblen und linken:

    as -o hello.o hello.asm
    ld -o hello.exe hello.o -LC:\MinGW\lib -luser32 -lkernel32
    hello.exe
    

    ... und eine MsgBox popt hoch mit dem Text.

    Funktioniert das bei dir auch so?



  • Ich habe das Beispiel auch kompiliert, und es funktionert auch bei mir.
    Dazu noch kurz eine Frage: Wie kann ich verhindern, dass, wenn ich das Programm starte, im Hintergrund ein Konsolenfenster aufpoppt? Beim gcc kann man das verhindern, wenn man beim Kompilieren "-mwindows" angibt. Aber wie kann man das beim Linken erzielen?

    Und noch eine Frage:
    Was genau sagen die Zahlen hinter den per .extern deklarierten Dateinamen?

    oenone schrieb:

    .extern _MessageBoxA@16
    .extern _ExitProcess@4
    

    Also das "@16" und das "@4"?

    Hat das was mit den Parametern zu tun, die die Funktion verlangt, also "ExitProcess" verlang als Parameter 4 Bytes, also einen Int?
    Hättest du vielleicht einen Link zur Gnu-Assembler-Dokumentation, wo das erklärt ist?



  • Probier mal "--subsystem windows", um das Konsolenfenster zu umgehen. Bei meinem Test kam übrigens keins, da ich die exe schon aus einem Konsolenfenster aufgerufen habe ^^'

    Du hast richtig geraten, die Zahl ist die Anzahl an Bytes. Das liegt nicht an GAS oder Assembler, sondern an der Win-API:
    http://msdn.microsoft.com/de-de/library/zxk0tw93.aspx

    (Siehe "Namensergänzungskonvention", da steht auch das mit dem "_")



  • Ok, und wenn eine Funktion keinen Parameter annimmt ( void ), dann "@0"?



  • Genau 🙂



  • Das Program ist trivial, es soll einfach nur das Clipboard leeren.

    .extern _OpenClipboard@4
    .extern _EmptyClipboard@0
    .extern _CloseClipboard@0
    .extern _ExitProcess@4
    
    .section .text
    .globl _start
    _start:
    	push $0
    	call _OpenClipboard@4
    	jz .error
    
    	call _EmptyClipboard@0
    	jz .error
    
    	call _CloseClipboard@0
    
    	push $0
    	call _ExitProcess@4
    
    .error:
    	push $1
    	call _ExitProcess@4
    

    Es lässt sich mittlerweile kompilieren, es scheint aber nicht zu funktioneren.

    Wenn ich einen Text in die Zwischenablage kopiere, und dann das Programm starte, so bleibt der Text in der Zwischenablage 😞

    Vielleicht könntest du mir ein weiteres mal helfen?



  • Ich habe meinen Fehler selbst gefunden: ich muss natürlich erstmal den Rückgabewert der Funktionen mit cmp überprüfen vor jz .

    cmp $0, %eax
    jz .error
    

    Aber Danke für deine sonstige Hilfe, oenone.


Anmelden zum Antworten