2017-07-23 102 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

好的。我现在明白了,并且已经与工作来源更新了操作。谢谢一堆! –

相关问题