64-Bit Linux, Assembly Language, Issues

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



Leave a reply



Submit