我似乎无法从WinAPI NASM教程中解决此LD错误

我似乎无法从WinAPI NASM教程中解决此LD错误,winapi,assembly,linker,nasm,ld,Winapi,Assembly,Linker,Nasm,Ld,就某些背景而言,我对汇编程序相当陌生,我选择的汇编程序是NASM。在我的第一个项目中,我在Windows 8.1上使用cygwin,我尝试将这个stackoverflow问题的第二个答案中的信息从32位转换为64位: 我使用GNULD而不是link.exe,因为我的系统上的kernel32.Lib似乎有问题,而且我还是更喜欢GNULD。这是我的汇编程序: global _main extern GetStdHandle@4

就某些背景而言,我对汇编程序相当陌生,我选择的汇编程序是NASM。在我的第一个项目中,我在Windows 8.1上使用cygwin,我尝试将这个stackoverflow问题的第二个答案中的信息从32位转换为64位:

我使用GNULD而不是link.exe,因为我的系统上的kernel32.Lib似乎有问题,而且我还是更喜欢GNULD。这是我的汇编程序:

            global  _main
            extern  GetStdHandle@4
            extern  WriteFile@20
            extern  ExitProcess@4

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

            ; hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)
            push            -11
            call            GetStdHandle@4
            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            WriteFile@20

            mov             rsp,    rbp
            pop             rbp

            ; ExitProcess(0)
            push            0
            call            ExitProcess@4

            ;
            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'
因此,我利用谷歌的优势发现了这个问题:

我阅读了第一个答案中的材料,搜索了谷歌更多信息,然后尝试了第二个答案中提供的解决方案。这是我的链接器脚本

    SECTIONS
    {
            . = 0x000000000000001b;
            .text :
            {
                    *(*)
            }
    }
我尝试使用以下命令链接:

    ld test.obj -T test.ld -lkernel32 --enable-stdcall-fixup /cygdrive/c/Windows/system32/kernel32.dll -o test.exe
我得到了这个错误:
ld:找不到-lkernel32

无论在哪里放置
-T test.ld
选项,我都会收到此错误

我被卡住了,我的google foo似乎不足以找到这样的帮助。我不明白为什么在指定链接器脚本时LD找不到kernel32,我也不知道如何解决截断问题

如果有帮助,则带有
test.obj
重定位数据的objdump是:

    $ 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        GetStdHandle@4
       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       WriteFile@20
      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       ExitProcess@4
      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)
在寄存器中具体传递前四个整数大小的参数,
RCX
RDX
R8
R9
。只有当参数超过4个时,才会在堆栈上传递它们。请注意,这与常见的32位调用约定不同,后者在堆栈上传递所有参数

也就是说,您的问题是生成32位重定位的
push消息
(因为
push
只需要32位立即数)。您应该做的是传递字符串的地址,因此,要解决这个问题,请使用

lea  rax, [rel message]
push rax
此处的
rel
关键字确保使用RIP相对地址,这是64位二进制文件的惯用方法。

在寄存器中专门传递前四个整数大小的参数,
RCX
RDX
R8
R9
。只有当参数超过4个时,才会在堆栈上传递它们。请注意,这与常见的32位调用约定不同,后者在堆栈上传递所有参数

也就是说,您的问题是生成32位重定位的
push消息
(因为
push
只需要32位立即数)。您应该做的是传递字符串的地址,因此,要解决这个问题,请使用

lea  rax, [rel message]
push rax

此处的
rel
关键字确保使用RIP相对地址,这是64位二进制文件的惯用方法。

好的,谢谢!二进制文件现在链接,但它会在WriteFile()调用上生成分段错误。这是因为x64上的调用约定(是ARM ABI吗?)。在这种情况下,我是否应该按照本页所述将参数移动到r寄存器中?:我已经将官方msdn文档链接到您了。。。不,这和手臂无关,好的。我现在得到了它,并用工作源代码更新了op。非常感谢!好的,谢谢!二进制文件现在链接,但它会在WriteFile()调用上生成分段错误。这是因为x64上的调用约定(是ARM ABI吗?)。在这种情况下,我是否应该按照本页所述将参数移动到r寄存器中?:我已经将官方msdn文档链接到您了。。。不,这和手臂无关,好的。我现在得到了它,并用工作源代码更新了op。非常感谢!