Author Topic: What is wrong?  (Read 12639 times)

Offline AzzozHSN

  • Jr. Member
  • *
  • Posts: 4
What is wrong?
« 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

Offline MrCBofBCinTX

  • Jr. Member
  • *
  • Posts: 18
    • Capuchado!
Re: What is wrong?
« Reply #1 on: July 17, 2010, 11:02:51 AM »
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

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: What is wrong?
« Reply #2 on: July 17, 2010, 12:13:11 PM »
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


Offline AzzozHSN

  • Jr. Member
  • *
  • Posts: 4
Re: What is wrong?
« Reply #3 on: July 17, 2010, 01:27:41 PM »
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?


Offline MrCBofBCinTX

  • Jr. Member
  • *
  • Posts: 18
    • Capuchado!
Re: What is wrong?
« Reply #4 on: July 17, 2010, 01:35:14 PM »
it should be ./test

Offline AzzozHSN

  • Jr. Member
  • *
  • Posts: 4
Re: What is wrong?
« Reply #5 on: July 17, 2010, 01:36:36 PM »
Thanks, I think it worked

Offline AzzozHSN

  • Jr. Member
  • *
  • Posts: 4
Re: What is wrong?
« Reply #6 on: July 17, 2010, 01:41:15 PM »
Okay, how can I use idiv or div ?

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: What is wrong?
« Reply #7 on: July 17, 2010, 02:21:05 PM »
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


Offline qiet72

  • Jr. Member
  • *
  • Posts: 6
Re: What is wrong?
« Reply #8 on: September 09, 2010, 01:18:48 PM »
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

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: What is wrong?
« Reply #9 on: September 10, 2010, 09:05:04 AM »
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


Offline Alex Holt

  • New Member
  • Posts: 1
Re: What is wrong?
« Reply #10 on: October 29, 2010, 04:22:53 PM »
Why doesn't the exit code work when using gcc as the linker instead of ld (eg, to call C functions with NASM)?
Code: [Select]
; 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

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: What is wrong?
« Reply #11 on: October 29, 2010, 06:54:07 PM »
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"!).

Code: [Select]
; 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:

Code: [Select]
; 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):

Code: [Select]
; 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