2016-03-24 8 views
2

Problem

Verknüpfung Wenn ich meinen Assembler-Code mit as (binutils) und Link mithilfe link.exe (Visual Studio 2015) stürzt das Programm wegen eines unrelocated Adresse kompilieren.Unrelocated Adresse, wenn sie mit link.exe

Bei der Verknüpfung mit gcc (gcc hello-64-gas.obj -o hello-64-gas.exe) läuft das Programm korrekt ohne Absturz obwohl. Gehe ich richtig davon aus, dass die Objektdatei, die von as erzeugt wird, compilerunabhängig sein sollte, da sich Abi-Kompatibilitätsprobleme in den Händen des Assembly-Code-Schreibers befinden? Da ich ein Anfänger bin, wird jede Erklärung meiner Fehler/falschen Annahmen geschätzt.

Plattform

  • 10 Windows 64-Bit-
  • Linker: Visual Studio 2015 die nativen Befehl Tools-Eingabeaufforderung (x64)
  • Compiler mit: as von MinGW-w64

Beispiel

Der folgende Code tut nicht Link richtig:

# hello-64-gas.asm print a string using printf 
# Assemble: as hello-64-gas.asm -o hello-64-gas.obj --64 
# Link:  link -subsystem:CONSOLE hello-64-gas.obj -out:hello-64-gas.exe libcmt.lib libvcruntime.lib libucrt.lib legacy_stdio_definitions.lib 
.intel_syntax noprefix 

.global main 

# Declare needed C functions 
.extern printf 

.section .data 
msg:  .asciz "Hello world" 
fmt:  .asciz "%s(%d; %f)\n" 
myDouble: .double 2.33, -1.0 

.text 
main: 
    sub rsp, 8*5 
    mov rcx, offset flat: fmt 
    mov rdx, offset flat: msg 
    mov r8, 0xFF 
    mov r9, offset flat: myDouble 
    mov r9, [r9] 
    movq xmm4, r9 
    call printf 
    add rsp, 8*5 

    mov rax, 0 
    ret 

Beim Debuggen es scheint mov r9, offset flat: myDouble nicht verlegt: mov r9,18h, wo 18h würde, wenn die .data wo an der Position Null korrekt sein. Mit Blick auf die Verschiebungstabelle mit objdump -dr hello-64-gas.obj ergibt:

... 
19: 49 c7 c1 18 00 00 00 mov $0x18,%r9 
         1c: R_X86_64_32S  .data 
... 

Variation (? Abhilfe)

Ersetzen mov mit movabs scheint zu funktionieren:

# hello-64-gas.asm print a string using printf 
# Assemble:  as hello-64-gas.asm -o hello-64-gas.obj --64 
# Link:   link -subsystem:CONSOLE hello-64-gas.obj -out:hello-64-gas.exe libcmt.lib libvcruntime.lib libucrt.lib legacy_stdio_definitions.lib 
.intel_syntax noprefix 

.global main 

# Declare needed C functions 
.extern printf 

.section .data 
msg:  .asciz "Hello world" 
fmt:  .asciz "%s(%d; %f)\n" 
myDouble: .double 2.33, -1.0 

.text 
main: 
    sub rsp, 8*5 
    movabs rcx, offset flat: fmt 
    movabs rdx, offset flat: msg 
    mov r8, 0xFF 
    movabs r9, offset flat: myDouble 
    mov r9, [r9] 
    movq xmm4, r9 
    call printf 
    add rsp, 8*5 

    mov rax, 0 
    ret 

Dies irgendwie richtig läuft bei Verwendung von link.exe verknüpft.

+1

Die dümmsten keine Forschungsfragen sind upvoted, aber wenn jemand tatsächlich versucht zu debuggen und sonst die Ursache des Problems zu finden, gibt die richtigen Details in einer gut formatierten Frage mit korrekten Tags und sogar einen Workaround, dann ist er downvoted? Ich verstehe diese Welt nicht mehr. – Jester

+0

@Jester, ich habe gerade uplooted ;-) aber ja, muss zugeben, das ist eine viel bessere Frage als das, was wir normalerweise sehen! –

Antwort

4

Die Verlagerung, die der GNU-Assembler für Ihre Verweise auf myDouble zusammen mit fmt und msg verwendet, wird von Microsoft-Linker nicht unterstützt. Diese Verschiebung, die von den GNU-Dienstprogrammen R_X86_64_32S genannt wird und einen Wert von 0x11 hat, ist in Microsoft's PECOFF specification nicht dokumentiert.Wie kann durch die Verwendung von Microsoft DUMPBIN auf Objektdatei belegt werden, scheint Microsofts Linker Verlagerungen mit diesem Wert für einen anderen Menschen ohne Papiere Zweck zu verwenden:

RELOCATIONS #1 
               Symbol Symbol 
Offset Type    Applied To   Index  Name 
-------- ---------------- ----------------- -------- ------ 
00000007 EHANDLER         7 .data 
0000000E EHANDLER         7 .data 
0000001C EHANDLER         7 .data 
00000029 REL32      00000000   C printf 

als Arbeit um Sie können entweder den Einsatz verwenden:

  • eine LEA-Anweisung mit RIP relativer Adressierung, die gefunden
  • wie Sie sich aus einer R_X86_64_PC32/REL32 Verlagerung erzeugt, ein MOVABS Befehl, die
  • einen 32-Bit-Befehl, der MOV g einer R_X86_64_64/ADDR64 Verlagerung erzeugt

    lea r9, [rip + myDouble] 
    movabs r9, offset myDouble 
    mov r9d, offset myDouble 
    

    Diese, zusammen mit mov r9, offset myDouble werden vier verschiedene Befehle mit unterschiedlichen Codierungen und subtil unterschiedliche Semantik jeweils eine andere Art von erfordern: enerates einen R_X86_64_32/ADDR32 Umzug

Um so werden diese würden geschrieben Umzug.

Der LEA-Befehl codiert myDouble als 32-Bit-Offset mit Vorzeichen im Verhältnis zu RIP. Dies ist die bevorzugte Anweisung, die hier verwendet werden soll, da nur 4 Byte zum Codieren der Adresse benötigt werden und die ausführbare Datei an beliebiger Stelle in den 64-Bit-Adressraum geladen werden kann. Die einzige Einschränkung ist, dass die ausführbare Datei weniger als 2G groß sein muss, aber das ist eine grundlegende Einschränkung x64 PECOFF ausführbare Dateien sowieso.

Der MOVABS codiert myDouble als absolute 64-Bit-Adresse. Während dies in der Theorie myDouble ermöglicht, irgendwo im 64-Bit-Adressraum zu liegen, sogar mehr als 2G weg von der Anweisung, dauert es 8 Byte Kodierungsraum und bringt Sie eigentlich nichts unter Windows.

Die 32-Bit-MOV-Anweisung codiert myDouble als vorzeichenlose 32-Bit-Absolutadresse. Es hat den Nachteil, dass die ausführbare Datei irgendwo in den ersten 4G des Adressraums geladen werden muss. Aus diesem Grund müssen Sie das Flag /LARGEADDRESSAWARE:NO mit dem Microsoft-Linker verwenden, sonst erhalten Sie einen Fehler.

Die 64-Bit-MOV-Anweisung, die Sie verwenden, codiert myDouble als 32-Bit-Absolutadresse mit Vorzeichen. Dies begrenzt auch, wo die ausführbare Datei geladen werden kann, und erfordert eine Art der Verlagerung, die das PECOFF-Format von Microsoft nicht enthält und die nicht vom Linker von Microsoft unterstützt wird.

+0

Also ist das ein Fehler in GNU oder sollen sie nicht kompatibel sein? –

+0

@HarryJohnston Ich würde es einen Fehler in GNU Binutils nennen. Obwohl sie nicht für diese spezielle Art der Verlagerung kompatibel sein sollten, handelt es sich um eine GNU-Erweiterung. Das Problem war, dass sie bei der Erstellung ihrer eigenen Relocation-Typen Werte auswählten, die die von Microsoft bereits definierten überlagerten. Dieser ist zufällig der letzte offiziell definierte Relocation-Typ. Wenn sie viel höhere Werte für den Relocation-Typ gewählt hätten, wären sie 16 Bit, und Microsoft Linker hätte sich über die unbekannte Verlagerung beschwert. –

Verwandte Themen