I'm in an interesting problem.I forgot I'm using 64bit machine & OS and wrote a 32 bit assembly code. I don't know how to write 64 bit code.
This is the x86 32-bit assembly code for Gnu Assembler (AT&T syntax) on Linux.
//hello.S
#include <asm/unistd.h>
#include <syscall.h>
#define STDOUT 1
.data
hellostr:
.ascii "hello wolrd\n";
helloend:
.text
.globl _start
_start:
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
Now, This code should run fine on a 32bit processor & 32 bit OS right? As we know 64 bit processors are backward compatible with 32 bit processors. So, that also wouldn't be a problem. The problem arises because of differences in system calls & call mechanism in 64-bit OS & 32-bit OS. I don't know why but they changed the system call numbers between 32-bit linux & 64-bit linux.
asm/unistd_32.h defines:
#define __NR_write 4
#define __NR_exit 1
asm/unistd_64.h defines:
#define __NR_write 1
#define __NR_exit 60
Anyway using Macros instead of direct numbers is paid off. Its ensuring correct system call numbers.
when I assemble & link & run the program.
$cpp hello.S hello.s //pre-processor
$as hello.s -o hello.o //assemble
$ld hello.o // linker : converting relocatable to executable
Its not printing helloworld
.
In gdb its showing:
I don't know how to debug in gdb. using tutorial I tried to debug it and execute instruction by instruction checking registers at each step. its always showing me "program exited with 01". It would be great if some on could show me how to debug this.
(gdb) break _start
Note: breakpoint -10 also set at pc 0x4000b0.
Breakpoint 8 at 0x4000b0
(gdb) start
Function "main" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Temporary breakpoint 9 (main) pending.
Starting program: /home/claws/helloworld
Program exited with code 01.
(gdb) info breakpoints
Num Type Disp Enb Address What
8 breakpoint keep y 0x00000000004000b0 <_start>
9 breakpoint del y <PENDING> main
I tried running strace
. This is its output:
execve("./helloworld", ["./helloworld"], [/* 39 vars */]) = 0
write(0, NULL, 12 <unfinished ... exit status 1>
write(0, NULL, 12)
system call in the output of strace?EDIT:
After reading Paul R's answer. I checked my files
claws@claws-desktop:~$ file ./hello.o
./hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
claws@claws-desktop:~$ file ./hello
./hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
I agree with him that these should be ELF 32-bit relocatable & executable. But that doesn't answer my my questions. All of my questions still questions. What exactly is happening in this case? Can someone please answer my questions and provide an x86-64 version of this code?
While 64-bit apps couldn't work on 32-bit OS, 32-bit apps could work on 64-bit OS but they need some 32-bit libraries to run. Since Ubuntu 11.04 (Natty) and Debian 7.0 (Wheezy) there has been support for multiarch, when 32-bit and 64-bit libraries could live on the same OS.
To put it in simple words, if you run a 32-bit program on a 64-bit machine, it will work fine, and you won't encounter any problems. Backward compatibility is an important part when it comes to computer technology. Therefore, 64 bit systems can support and run 32-bit applications.
To install 32-bit libraries on Ubuntu 13.04 (64-bit) or later, open Terminal and type: sudo apt-get install lib32z1 (you will need to enter your password). Then just for good measure, let's make sure your Ubuntu is up to date. Type sudo apt-get update and lastly, restart your computer.
You can't directly link to 32bit code inside of a 64bit program. The best option is to compile a 32bit (standalone) program that can run on your 64bit platform (using ia32), and then use a form of inter-process communication to communicate to it from your 64bit program.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With