64-bit linux, Assembly Language, Issues?
Your code examples should all still work. 64-bit processors and operating systems can still run 32-bit code in a sort of "compatability mode". Your assembly examples are no different. You may have to provide an extra line of assembly or two (such as .BITS 32) but that's all.
In general, using a 64-bit OS will be faster than using a 32-bit OS. x86_64 has more registers than i386. Since you're working on assembly, you already know what registers are used for... Having more of them means less stuff has to be moved on and off the stack (and other temporary memory) thus your program spends less time managing data and more time working on that data.
Edit: To compile 32-bit code on 64-bit linux using gas, you just use the commandline argument "--32", as noted in the GAS manual
Errors when linking 32/64bit assembly in Linux
This applies to Linux Mint, Ubuntu, Xubuntu and other modern Ubuntu based distributions. For other Debian systems the information is the same, but you can remove the sudo
command from the installation command and run the command as the root
user.
By default files needed for GCC to create 32-bit program are not installed on 64-bit Linux Mint. This command will install the required files:
sudo apt-get install gcc-multilib g++-multilib
To assemble asa 32-bit object, and then link to a 32-bit executable you can do this:
nasm -f elf32 tiny.asm -o tiny.o
gcc -m32 -Wall -s tiny.o -o tiny
Since you had BITS 32
at the top of the assembler file you want to compile that to a 32-bit ELF object which is what the -f elf32
option on the NASM command line does.
GCC is used to link objects to a final executable. The addition of -m32
tells GCC to link the objects to a 32-bit executable. The -m32
option overrides the normal default behavior of generating 64-bit executables on a 64-bit Linux distribution.
By using GCC to link the executable, the generated program actually supplies a _start
that does C runtime initialization and then calls the label called main
as if it was a C function.
When you do the ret
in your main
function it returns back to the C runtime code and exits the program cleanly for you.
Using GCC is the easier and safer method for new assembly language developers. It also allows you to add code that calls the C runtime functions like printf
, scanf
, atoi
and most of the other standard C library functions.
Running 32 bit assembly code on a 64 bit Linux & 64 bit Processor : Explain the anomaly
Remember that everything by default on a 64-bit OS tends to assume 64-bit. You need to make sure that you are (a) using the 32-bit versions of your #includes where appropriate (b) linking with 32-bit libraries and (c) building a 32-bit executable. It would probably help if you showed the contents of your makefile if you have one, or else the commands that you are using to build this example.
FWIW I changed your code slightly (_start -> main):
#include <asm/unistd.h>
#include <syscall.h>
#define STDOUT 1
.data
hellostr:
.ascii "hello wolrd\n" ;
helloend:
.text
.globl main
main:
movl $(SYS_write) , %eax //ssize_t write(int fd, const void *buf, size_t count);
movl $(STDOUT) , %ebx
movl $hellostr , %ecx
movl $(helloend-hellostr) , %edx
int $0x80
movl $(SYS_exit), %eax //void _exit(int status);
xorl %ebx, %ebx
int $0x80
ret
and built it like this:
$ gcc -Wall test.S -m32 -o test
verfied that we have a 32-bit executable:
$ file test
test: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.4, dynamically linked (uses shared libs), not stripped
and it appears to run OK:
$ ./test
hello wolrd
Confused about 64-bit registers - ASM
Run strace ./my_program
- you make a bogus stat
system call, then write
which succeeds, then fall off the end and segfault.
$ strace ./foo
execve("./foo", ["./foo"], 0x7ffe6b91aa00 /* 51 vars */) = 0
stat(0x1, 0x401000) = -1 EFAULT (Bad address)
write(0, "Hello, World\n", 13Hello, World
) = 13
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xd} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)
It's not register names that are your problem, it's call numbers. You're using 32-bit call numbers but calling the 64-bit syscall
ABI.
Call numbers and calling convention both differ.
int 0x80
system calls only ever look at the low 32 bits of registers which is why you shouldn't use them in 64-bit code.
The code you posted in a comment with mov rcx, message
would work fine with mov ecx, message
and so on, if it works with mov rcx, message
. See What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?.
Note that writing a 32-bit register zero-extends into the full 64-bit register so you should always use mov edi, 1
instead of mov rdi, 1
. (Although NASM will do this optimization for you to save code-size; they're so equivalent that some assemblers will silently do it for you.)
64 Bit Assemblers issue
FASM does have x64 support. Did you read the manual? Did you look at the examples in *EXAMPLES\WIN64*?
X86 64-bits Assembly Linux 'Hello World' linking issue
GCC in Debian Stretch defaults to building position independent executables, to build executable linked to specific address as is traditional pass -no-pie
to GCC.
Alternatively specify the correct relocation type, I don't know how to do this in yasm.
Related Topics
Cdc_Acm: Failed to Set Dtr/Rts - Can Not Communicate with Usb Cdc Device
Recording from Alsa - Understanding Memory Mapping
How to Configure Gitlab as a Subdomain in Nginix.Conf
Cache Coloring on Slab Memory Management in Linux Kernel
Force Netcat to Send Messages Immediately (Without Buffering)
Conditional Awk Hashmap Match Lookup
How to Authenticate Username/Password Using Pam W/O Root Privileges
Reliably Kill Sleep Process After Usr1 Signal
Automate Scp with Multiple Files with Expect Script
Using Linux Virtual Mouse Driver
Sharing Stdout Among Multiple Threads/Processes
Docker - Is It Safe to Switch to Non-Root User in Entrypoint
What Does "Private_Dirty" Memory Mean in Smaps
Jetty Bash Script Works Only with Root User