I'm trying to use MinGW-w64 to compile assembly code on Windows. The test code I am trying to compile is (I'm sure this code extremely bad, but the problem lies in the linker, not the actual code):
.intel_syntax noprefix
.text
.globl _start
_start:
push rbp
mov rbp, rsp
and rsp, -64
sub rsp, 64
mov rax, 0
leave
push 0
call _ExitProcess#4
And the command for I used for compiling is this:
gcc -nostdlib simpletest.s -o out.exe
It doesn't matter to the outcome if I add -kernel32 at the end of the command or not.
No matter what I try I keep getting the following error:
Undefined reference to '_ExitProcess#4'
I should add that the same gcc is perfectly capable of compiling C code to assembly, and then compile that assembly code to an exe.
Related
I want to play a bit with assembly. To get started I've created a little asm script and tried to compile it. In the first step everything went great:
nasm -felf64 hello.asm
But when I tried to use
ld -o hello.o hello
from MinGW an error occured:
hello.o: file not recognized: File format not recognized
What can I do to fix this problem? I've tried it with gcc as well but then the same error plus one other error occurs.
MinGW creates binaries targeting Windows. Windows does not support ELF binaries (or does it? with Windows subsystem for Linux?). Anyway, ld in MinGW will expect that you provide binaries in win64 format not elf64.
nasm -fwin64 hello.asm will most likely work.
No it won't work because I just saw your code, and you are using Linux syscalls under Windows.
Write,
mov rcx, 69
call ExitProcess
instead of,
mov rax, SYS_EXIT
mov rdi, 69
syscall
Leave a comment if it doesn't work.
I've been using Visual Studio to assemble and link cpp programs that include masm (.asm) files. I want to be able to do this myself, on the command line. I used the ml.exe that Visual Studio provides to assemble my masm code (at Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x86\ml.exe).
However, when I try to compile my project with gcc main.cpp fib.obj -o main, I get an error saying that the .obj architecture does not match the target architecture (i386 architecture of input file 'fib.obj' is incompatible with i386:x86-64 output).
So my question is, simply, how do I compile this project?
What I've Tried
The two things that I've done to get different errors (which I think are more promising) are (1) to utilize the ml64 executable from ...\Hostx86\x64\ml64.exe or ...\Hostx64\x64\ml64.exe, and (2) to use the -m32 option for gcc.
ml64
Using ml64 I have been unable to assemble my masm code. with the following source file, ml64 spits out this response:
; int fib(int);
.386
.model flat, c
.code
fib proc uses ebx ecx, i:dword
mov eax, 0 ; current fib number
mov ebx, 1 ; next fib number
while_1:
cmp i, 0
jle while_1_end
; add eax -> ebx and mov previous ebx into eax
mov ecx, ebx ; store new current fib number
add ebx, eax ; sum previous fib numbers
mov eax, ecx ; set eax to current fib value
dec i
jmp while_1
while_1_end:
; the ith fib number is in eax
ret
fib endp
end
...\fib> ml64 fib.asm
Microsoft (R) Macro Assembler (x64) Version 14.29.30136.0
Copyright (C) Microsoft Corporation. All rights reserved.
Assembling: fib.asm
fib.asm(2) : error A2008:syntax error : .
fib.asm(3) : error A2008:syntax error : .
fib.asm(6) : error A2008:syntax error : ebx
fib.asm(24) : fatal error A1010:unmatched block nesting : fib
I presume that .386 isn't right for a x64 target, but removing it changes the error very little (it only removes the syntax error line 2).
I don't really want to use x64 assembly if it isn't the same as x32, but I'll use this solution if it works. I think my second option is more promising.
gcc -m32
I don't believe I can tell gcc to build to a 32-bit target because I don't have 32-bit versions of the libraries. When running gcc -m32 main.cpp fib.obj I get cannot find -lmingw32, cannot find -lgcc, cannot find -lgcc_ex, etc. Should I get these libraries, and if so, where do I find them? It seems a bit awful to download 32-bit libraries on my x64 computer just to assemble masm, and I don't think I should have to, seeing as Visual Studio is able to compile my project simply by setting the target to Win32.
Is there a different way of telling gcc to target 32-bit architecture, or are the libraries perhaps hidden in the Visual Studio files, or something else? I'm pretty sure that if I could get gcc to target x32, it would solve my problem, because Visual Studio targets x32, and when I change the target to x64 I get the same error I have been getting (module machine type 'x86' conflicts with target machine type 'x64').
I was trying to build an exe from asm file. The asm file looks like this:
global main
extern puts
section .data
msg:
db "Hello, world!",10,0
section .text
main:
sub rsp, 28h
mov rcx, msg
call puts
add rsp, 28h
ret
Then I assembled it using NASM and tried to link it using GCC. But it is showing this error.
> nasm -fwin64 asmtest.asm
> gcc asmtest.obj
asmtest.obj: file not recognized: File format not recognized
collect2.exe: error: ld returned 1 exit status
I am unable to figure out what is going on. My NASM version 2.14.02 and GCC version 8.1.0. I have followed this tutorial (at the bottom). I am doing this on my Windows 10 64-bit machine.
I have also seen this question, but it didn't help me.
You have installed mingw for 32 bit binaries. You need to install a version of mingw configured to make 64 bit binaries to compile and/or link 64 bit binaries.
I would like to compile "Hello World" in Windows Subsystem for Linux (WLS) with Debian.
.text
.global _start
_start:
movl $len,%edx
movl $msg,%ecx
movl $1,%ebx
movl $4,%eax
int $0x80
movl $0,%ebx
movl $1,%eax
int $0x80
.data
msg:
.ascii "Hello, world!\n"
len = . - msg
If i compile in a Debian server with
gcc -nostdlib -o hello hello.s
It work, but in WLS return error
/usr/bin/ld: /tmp/cciVVddg.o: relocation R_X86_64_32 against `.data' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output collect2: error: ld returned 1 exit status
I also tried
gcc -fPIC -nostdlib -o hello hello.s
There are two problems with your code:
your code is intended to be 32 bit code but gcc tries to assemble it as 64 bit code. You can fix this by passing -m32 in all stages of assembly and linkage. Please keep in mind that WSL does not actually support 32 bit code so you won't be able to run your program even if you manage to assemble it.
gcc tries to generate a position-indepentent executable. To make your code work in such an executable, you need to write position indepentent code. To do so, you need to avoid any absolute references to the addresses of variables. In 32 bit code, this is a bit tricky and I'm not going to explain this further as 32 bit code won't run on WSL anyway. The compiler advises you to compile with -fpic because that causes the compiler to generate position independent code from C files, but for assembly files it's ineffective. You can fix this issue by linking with -no-pie, causing the linker to generate a normal position-dependent binary. Note that this still doesn't mean that a 32 bit binary is going to run in WSL.
I'm trying to compile the following using gcc -c main.s
.intel_syntax noprefix
.global main
main:
push ebp
mov ebp,esp
sub esp,0x10
mov DWORD PTR [ebp-0xc],0x0
mov eax,DWORD PTR [ebp+0xc]
mov eax,DWORD PTR [eax+0x4]
mov DWORD PTR [ebp-0x4],eax
leave
ret
And I get an error:
main.s:6: Error: operand type mismatch for `push'
What's the reason this isn't working?
From the Intel® 64 and IA-32 Architectures Software Developer’s Manual, 7.3.1.5 Stack Manipulation Instructions in 64-Bit Mode:
In 64-bit mode, the stack pointer size is 64 bits and cannot be overridden by an instruction prefix. In implicit stack references, address-size overrides are ignored. Pushes and pops of 32-bit values on the stack are not possible in 64-bit mode.
(Emphasis mine.)
push ebp tries to push a 32-bit register, which is not allowed in 64-bit mode.
This is 32-bit code (and would crash in 64-bit mode even if push ebp was encodeable), so you need to assemble it into a 32-bit executable. With gcc or clang, use
gcc -m32 -no-pie -fno-pie main.s -o my_prog
(The no-pie options are not necessary, but you probably want them to get a simpler position-dependent executable for 32-bit code.)