For some background, I'm pretty new to assembler, and my assembler of choice is NASM. For my first project, I'm using cygwin on Windows 8.1, and I've tried to convert the information from the second answer on this stackoverflow question from 32 bit to 64 bit: How to write hello world in assembler under Windows?
I'm using gnu ld instead of link.exe because the kernel32.Lib on my system seems to be messed up, and I prefer gnu ld anyway. So, this is my assembler:
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
When I run nasm -fwin64 ./test.asm
it assembles with no errors, only warnings about me leaving out the colons on the label names.
The command I'm using to link to the WinAPI is
ld test.obj -lkernel32 --enable-stdcall-fixup /cygdrive/c/Windows/system32/kernel32.dll -o test.exe
This leaves me with
test.obj:./test.asm:(.text+0x1c): relocation truncated to fit: R_X86_64_32 against `.text'
So, I used google to my advantage and found this stackoverflow question: What does this GCC error "... relocation truncated to fit..." mean?
I read the material in the first answer, and scoured google some more, and then tried the solution offered in the second answer. Here is my linker script
SECTIONS
{
. = 0x000000000000001b;
.text :
{
*(*)
}
}
I try to link using this command:
ld test.obj -T test.ld -lkernel32 --enable-stdcall-fixup /cygdrive/c/Windows/system32/kernel32.dll -o test.exe
And I get this error:
ld: cannot find -lkernel32
I get this error regardless of where I place the -T test.ld
option.
I'm stuck and my google-foo doesn't seem adequate enough to find help that way. I don't understand why LD can't find kernel32 when I specify a linker script, and I don't know how to resolve the truncation either.
If it helps, the objdump with relocation data for test.obj
is:
$ 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)
Thanks.
__SOLUTION EDIT__ for future google monkeys:
Using the information in the answer from @Jester, I rewrote the program and it now works as expected. Here is the working source:
global main
extern GetStdHandle@4
extern WriteFile@20
extern ExitProcess@4
section .text
main
push rbp
mov rbp, rsp
sub rsp, 8
; hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)
; ABI, pass in registers
mov rcx, -11
call GetStdHandle@4
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 WriteFile@20
mov rsp, rbp
pop rbp
; ExitProcess(0)
mov rcx, 0
call ExitProcess@4
;
hlt
message db 'Hello, World!', 10
message_end