On Wed, 11 Nov 2009 14:43:21 -0500, David Jackson <norsta...@gmail.com> wrote: > I am having great difficulty running a very simple assembler program > on FreeBSD on x86 in my efforts to learn some assembly programming on > FreeBSD. I have tried to compile the following with nasm, however i > get nothing in response when I attempt to run this program: > > section .data > hello db 'Hello, World!', 0xa > hbytes equ $ - hello > > section .text > global _start > _start: > push dword hbytes > push dword hello > push dword 1 > mov eax,0x4 > int 0x80 > add esp,12 > > push dword 0 > mov eax,0x1 > int 0x80 > > nasm -f elf -o hello1s.o hello1.s > ld -s -o hello1s hello1s.o > > ./hello1s prints nothing. > > What is wrong here? It should print "hello world". > Thanks in advance for your help, it is greatly appreciated.
Hi David. The truss utility is your friend when you are trying to decipher system call problems. It can translate system call arguments to human-readable output; a very useful property when debugging issues like this. For example here's the output for your original code: $ truss ./hello write(134516904,0xe,1) ERR#9 'Bad file descriptor' process exit, rval = 1 Note how the arguments of write() are 'misplaced'? The answer is that you are not calling the system call with C-like conventions (including a function call return address). The calling conventions of system calls are described in the Developer's Handbook at: http://www.freebsd.org/doc/en/books/developers-handbook/x86-system-calls.html You are missing a dword push before interrupting. As the dev handbook says, you have to use C calling conventions or push an extra (ignorable) dword before interrupting: An assembly language program can do that as well. For example, we could open a file: | kernel: | int 80h ; Call kernel | ret | | open: | push dword mode | push dword flags | push dword path | mov eax, 5 | call kernel | add esp, byte 12 | ret This is a very clean and portable way of coding. If you need to port the code to a UNIX system which uses a different interrupt, or a different way of passing parameters, all you need to change is the kernel procedure. But assembly language programmers like to shave off cycles. The above example requires a call/ret combination. We can eliminate it by pushing an extra dword: | open: | push dword mode | push dword flags | push dword path | mov eax, 5 | push eax ; Or any other dword | int 80h | add esp, byte 16 So by pushing *one* more dword before you interrupt should work fine (and it does, from a small test I ran just now): : keram...@kobe:/home/keramida$ cat hello.s : section .data : hello db 'Hello, World!', 0xa : hbytes equ $ - hello : : section .text : global _start : _start: : push dword hbytes : push dword hello : push dword 1 : push dword 0 ;or any other dword : mov eax, 4 : int 0x80 : add esp, byte 16 : : push dword 0 : push dword 0 ;ignored dword : mov eax, 1 : int 0x80 : add esp, byte 8 ;NOT REACHED : keram...@kobe:/home/keramida$ nasm -f elf -o hello.o hello.s : keram...@kobe:/home/keramida$ ld -s -o hello hello.o : keram...@kobe:/home/keramida$ truss ./hello : Hello, World! : write(1,"Hello, World!\n",14) = 14 (0xe) : process exit, rval = 0 : keram...@kobe:/home/keramida$ HTH, Giorgos _______________________________________________ firstname.lastname@example.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-questions To unsubscribe, send any mail to "freebsd-questions-unsubscr...@freebsd.org"