NASM - The Netwide Assembler
NASM Forum => Using NASM => Topic started by: AzzozHSN on July 17, 2010, 10:44:47 AM
-
Hello every one.
I'm trying to build a compiler. I need first to learn much about NASM. I wrote this code, noting wrong in assembling but when I try to execute the object program I have a message "bash: ./test.o: Permission denied"
section .bss
c RESW 1
d RESW 1
a RESW 1
tmp1 RESW 1
section .text
global start
start:
; a = 1
MOV DWORD [a], 1
MOV EAX, [a]
; d = a + 5;
ADD EAX, 5
MOV DWORD [d], EAX
; c = a * d;
MOV EAX, [a]
IMUL DWORD [d]
; a = c / d;
MOV DWORD [c], EAX
IDIV DWORD [d]
MOV DWORD [a], EAX
; exit
MOV EAX, 1
MOV EBX, 0
INT 0x80
-
a RESW 1
and
MOV DWORD [a], 1
I am very new to this, but do these work with the size mismatched?
Should it be:
MOV WORD [a], 1
or instead:
a RESD 1
-
I hardly know where to begin! :)
MrCBofBCinTX identifies what is perhaps the "biggest" problem. It'll "work" with mismatched sizes, but not as (presumably) intended. "mov dword[a], 1" overwrites "tmp1" as well as "a"! You almost certainly want to change all the "resw"s to "resd"s.
The default entrypoint known to ld is "_start", not "start" (yes, you need to use ld - one does not execute an .o file, generally). You can tell ld to use a different entrypoint with the "-e" switch, but it's probably easier to just add the underscore (both the "global" declaration and the label itself).
Your code itself is pretty good, until you get to the "idiv". "idiv" (and "div") are somewhat tricky, since some of the operands are not explicitly stated. In particular, "idiv", with a dword (stated) operand, divides edx:eax (edx * 4G + eax) by... whatever you say. If the result of this division won't fit in eax, it causes an exception, crashing your program. The error message presented is likely to be "division by zero" (dos) or "floating point error" (Linux) - not very helpful, since we didn't do either! The way to fix this is to put a "cdq" (convert dword to qword - works with eax and edx, again "unstated") immediately before the "idiv".
When you get to the end, there's a "trick" you can use... Since you don't (yet) have a way to display the result, you can make it the exit code - instead of "mov ebx, 0" do "mov ebx, [a]". Then you can see it with "echo $?" - immediately after running your program... when you get it to run :)
Now assemble it with "nasm -f elf32 myprog.asm", as you've apparently done, and link the object file into an executable with "ld -o myprog myprog.o". Then you should be able to run it, and see the result with "echo $?". The exit code is only good for a byte, but it should work for the small values you're currently using.
If you really, really don't want to use ld, there's a way around that which we can show you, but it's easier(?) and more flexible(!) to let ld do its intended job.
Best,
Frank
-
Thank you very much, I changed and shorted the program to become this:
section .bss
d RESD 1
a RESD 1
section .text
global _start
_start:
MOV DWORD [a], 1 ; a = 1
MOV EAX, [a]
ADD EAX, 5
MOV DWORD [d], EAX ; d = a + 5;
MOV EAX, [a]
MOV EAX, 1
MOV EBX, 0
INT 0x80
and then compiled it like this:
nasm -f elf32 test.asm
ld -o test test.o
./test.o
I got "Permission denied" then I used "echo $?" I got 126, what should I do? can you provide an example to learn from it?
-
it should be ./test
-
Thanks, I think it worked
-
Okay, how can I use idiv or div ?
-
Old instruction set reference, formerly part of the Nasm manual:
http://home.myfairpoint.net/fbkotler/nasmdocr.html
Note that for "echo $?" to display the result, you've gotta put it in ebx (just bl actually displays).
You're closing in on it!
Best,
Frank
-
Hi,
I just joined the list. This post was very helpful in learning how variables worked in assembler. I have his code so that it works as intended. He is my version:
section .bss
d RESD 1 ; Reserve a double word variable called "d"
a RESD 1 ; Reserve a double word variable called "a"
section .text
global _start
_start:
MOV DWORD [a], 1 ; move the double word value 1 to variable a
MOV EAX, [a] ; move the value of variable a to register EAX
ADD EAX, 5 ; add the value 5 to the value in EAX
MOV DWORD [d], EAX ; move the double word value in EAX to the variable "d"
MOV EAX, 1 ; set EAX to "1" (INT 80 function "exit")
MOV EBX, [d] ; move the exit value in variable "d" to EBX
INT 0x80 ; return the error code in EBX to the os
Hope I understood it right. :-)
Btw, I know that the .text section is where the code is and that you usually start with a global "__start", but what is the .bss section? Is it only for reserving variables?
Quinn
-
Right. Originally stood for "Block Started by Symbol" or some such. It is for uninitialized data. (nominally "uninitialized" it is in fact initialized to zero). You should only use the "res?" family of pseudo-instructions in it. My personal favorite reserves ten bytes - "rest". :)
".text" has always sounded to me like it should be where "Hello World" lives, but no, it's code.
For other section names known to Nasm in elf32/elf64 output format
http://www.nasm.us/doc/nasmdoc7.html#section-7.9.2
Best,
Frank
-
Why doesn't the exit code work when using gcc as the linker instead of ld (eg, to call C functions with NASM)?
; Compiled, linked, and run with:
; nasm -f elf sand.asm
; gcc -o sand sand.o
; ./sand
SECTION .text
global main
main:
mov ebx,12 ; return value, but checking with echo $? gives different numbers
; each time this program is run
ret
-
Putting the "exit code" in ebx works only with "int 80h". A C function ("main") expects the return value in eax (and expects ebx to be "preserved"!).
; Compiled, linked, and run with:
; nasm -f elf sand.asm
; gcc -o sand sand.o
; ./sand
SECTION .text
global main
main:
mov eax,12 ; return value
ret
Or:
; Compiled, linked, and run with:
; nasm -f elf sand.asm
; gcc -o sand sand.o
; ./sand
SECTION .text
global main
main:
mov ebx,12 ; return value
mov eax, 1 ; __NR_exit
int 80h
Or even use the "exit()" C function (a C function expects its parameter on the stack):
; Compiled, linked, and run with:
; nasm -f elf sand.asm
; gcc -o sand sand.o
; ./sand
SECTION .text
global main
extern exit
main:
push12 ; return value
call exit
Previous examples have used "_start" as an entrypoint. You can't "ret" from such a program - "_start" wasn't called! If you use gcc to link this (nothing to "compile" really, gcc just invokes ld), it'll complain about "_start" already being defined - it exists in the startup code which calls main. "gcc -nostartfiles ..." will work, or you can link such a program directly with ld. If you have "extern printf", for example, "ld -o myprog myprog.o -I/lib/ld-linux.so.2 -lc" - ld wants "lib/ld-linux.so.1" by default, and this probably doesn't exist -> "no such file or directory" (highly confusing - "myprog" is right there!) I'm surprised we haven't encountered this in this thread - I guess because it applies only if you're linking against libc. We probably "shouldn't" call C library functions without linking in that "startup" code, but my experience is that it works fine.
Best,
Frank