2017-07-23 101 views
0

對於某些背景,我對彙編器很陌生,我的彙編器是NASM。對於我的第一個項目,我在Windows 8.1上使用了cygwin,並且試圖將來自第二個答案的信息從32位轉換爲64位:How to write hello world in assembler under Windows?我似乎無法從WinAPI NASM教程中解決這個LD錯誤

我正在使用gnu ld的鏈接。因爲我的系統上的kernel32.Lib似乎搞砸了,而且我更喜歡gnu ld。所以,這是我的彙編:

  global _main 
      extern [email protected] 
      extern [email protected] 
      extern [email protected] 

      section .text 
    _main 
      push   rbp 
      mov    rbp, rsp 
      sub    rsp, 4 

      ; hStdOut = GetStdHandle(STD_OUTPUT_HANDLE) 
      push   -11 
      call   [email protected] 
      mov    rbx, rax 

      ; WriteFile(hStdOut, message, length(message), &bytes, 0) 
      push   0 
      lea    rax, [rbp-4] 
      push   rax 
      push   (message_end - message) 
      push   message 
      push   rbx 
      call   [email protected] 

      mov    rsp, rbp 
      pop    rbp 

      ; ExitProcess(0) 
      push   0 
      call   [email protected] 

      ; 
      hlt 

    message   db  'Hello, World!', 10 
    message_end 

當我運行nasm -fwin64 ./test.asm它沒有錯誤,只有我的警告留出的標籤名稱的冒號組裝。

我使用鏈接到WinAPI的命令是

ld test.obj -lkernel32 --enable-stdcall-fixup /cygdrive/c/Windows/system32/kernel32.dll -o test.exe 

這給我留下了

test.obj:./test.asm:(.text+0x1c): relocation truncated to fit: R_X86_64_32 against `.text' 

所以,我用谷歌對我有利,發現這個計算器的問題: What does this GCC error "... relocation truncated to fit..." mean?

我在第一個答案中閱讀材料,並搜索了一些谷歌,然後嘗試第二個答案中提供的解決方案。這裏是我的鏈接腳本

SECTIONS 
    { 
      . = 0x000000000000001b; 
      .text : 
      { 
        *(*) 
      } 
    } 

我嘗試使用此命令鏈接:

ld test.obj -T test.ld -lkernel32 --enable-stdcall-fixup /cygdrive/c/Windows/system32/kernel32.dll -o test.exe 

而且我得到這個錯誤:在這裏我放置-T test.ld ld: cannot find -lkernel32

不管我得到這個錯誤選項。

我被卡住了,我的google-foo似乎還不足以找到幫助。我不明白爲什麼LD在指定鏈接器腳本時找不到kernel32,而且我也不知道如何解決截斷問題。

如果有幫助,與拆遷數據objdump的爲test.obj是:

$ objdump -Sr test.obj 

    test.obj:  file format pe-x86-64 


    Disassembly of section .text: 

    0000000000000000 <_main>: 
     0: 55      push %rbp 
     1: 48 89 e5    mov %rsp,%rbp 
     4: 48 83 ec 04    sub $0x4,%rsp 
     8: 6a f5     pushq $0xfffffffffffffff5 
     a: e8 00 00 00 00   callq f <_main+0xf> 
          b: R_X86_64_PC32  [email protected] 
     f: 48 89 c3    mov %rax,%rbx 
     12: 6a 00     pushq $0x0 
     14: 48 8d 45 fc    lea -0x4(%rbp),%rax 
     18: 50      push %rax 
     19: 6a 0e     pushq $0xe 
     1b: 68 32 00 00 00   pushq $0x32 
          1c: R_X86_64_32 .text 
     20: 53      push %rbx 
     21: e8 00 00 00 00   callq 26 <_main+0x26> 
          22: R_X86_64_PC32  [email protected] 
     26: 48 89 ec    mov %rbp,%rsp 
     29: 5d      pop %rbp 
     2a: 6a 00     pushq $0x0 
     2c: e8 00 00 00 00   callq 31 <_main+0x31> 
          2d: R_X86_64_PC32  [email protected] 
     31: f4      hlt 

    0000000000000032 <message>: 
     32: 48      rex.W 
     33: 65 6c     gs insb (%dx),%es:(%rdi) 
     35: 6c      insb (%dx),%es:(%rdi) 
     36: 6f      outsl %ds:(%rsi),(%dx) 
     37: 2c 20     sub $0x20,%al 
     39: 57      push %rdi 
     3a: 6f      outsl %ds:(%rsi),(%dx) 
     3b: 72 6c     jb  a9 <message_end+0x69> 
     3d: 64 21 0a    and %ecx,%fs:(%rdx) 

感謝。

爲未來的谷歌猴子__SOLUTION EDIT__:

使用從@Jester答案的信息,我重寫了程序,現在按預期工作。下面是工作源:

   global main 
       extern [email protected] 
       extern [email protected] 
       extern [email protected] 

       section .text 
     main 
       push   rbp 
       mov    rbp, rsp 
       sub    rsp, 8 

       ; hStdOut = GetStdHandle(STD_OUTPUT_HANDLE) 
       ; ABI, pass in registers 
       mov    rcx, -11 
       call   [email protected] 
       mov    rbx, rax 

       ; WriteFile(hStdOut, message, length(message), &bytes, 0) 
       mov    rcx, rbx 
       lea    rax, [rel message] 
       mov    rdx, rax 
       mov    r8,  (message_end - message) 
       lea    rax, [rbp-8] 
       mov    r9,  rax 
       push   0 
       call   [email protected] 

       mov    rsp, rbp 
       pop    rbp 

       ; ExitProcess(0) 
       mov    rcx, 0 
       call   [email protected] 

       ; 
       hlt 

     message   db  'Hello, World!', 10 
     message_end 

回答

2

Windows 64-bit calling convention通過在寄存器特異性,RCXRDXR8,和R9前四個整數大小的參數。只有有超過4個參數時,它們纔會傳遞到堆棧上。請注意,這是,不同於的常見32位調用約定,它們在堆棧上傳遞全部參數。

這就是說,你的問題是push message生成一個32位重定位(因爲push只需要一個32位立即)。你應該做的是通過地址的字符串,所以,要解決這個問題,請使用例如。

lea rax, [rel message] 
push rax 

這裏的rel關鍵字確保了RIP-相對地址被使用,其是常用於64位二進制文​​件。

+0

好的,謝謝!二進制文件現在鏈接,但它在WriteFile()調用上生成分段錯誤。這是因爲x64上的調用約定(是ARM ABI嗎?)。在這種情況下,我是否應該按照本頁所述將參數移動到r寄存器中:http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/ –

+0

I已經將你的官方msdn文檔鏈接到了......並且不,它與ARM無關。 – Jester

+0

好的。我現在明白了,並且已經與工作來源更新了操作。謝謝一堆! –

相關問題