1

I`m trying to make a while loop that prints from 0 through 10 but have some errors...

Compile with these:

nasm -f elf myprog.asm
gcc -m32 -o myprog myprog.o

Errors:

at output you can see 134513690.. lots of.... and at the last line a segmentation fault

This is the code:

SECTION .text

global main

extern printf

main:
  xor eax,eax        ; eax = 0

myloop:
  cmp eax,10         ; eax = 10?
  je finish          ; If true finish

  push eax           ; Save eax value
  push number        ; push  number value on stack
  call printf

  pop eax
  inc eax            ; eax + 1
  add esp,80         ; Im not sure what is this
  jmp myloop         ; jump to myloop

number db "%d",10,0 ; This is how i print the numbers

finish:
  mov eax,1
  mov ebx,0
  int 0x80
Joel C
  • 2,958
  • 2
  • 15
  • 18
Bit87
  • 65
  • 9
  • You should save/restore ebx at the start/end of main, and use it for your loop counter. EBX is preserved across function calls in the normal ABI: http://stackoverflow.com/a/34100481/224132 – Peter Cordes Dec 06 '15 at 16:40
  • Thanks, I will try it :) – Bit87 Dec 07 '15 at 03:14

2 Answers2

1

There's one real error in this code; the function call cleanup isn't quite right. I would change the myloop section to be like this:

myloop:
  cmp eax,10         ; eax = 10?
  je finish          ; If true finish

  push eax           ; Save eax value
  push number        ; push  number value on stack
  call printf

  add esp, 4         ; move past the `push number` line
  pop eax
  inc eax            ; eax + 1
  jmp myloop         ; jump to myloop

The biggest difference is that instead of adding 80 to esp (and I'm not sure why you were doing that), you're only adding the size of the argument pushed. Also, previously the wrong value was getting popped as eax, but switching the order of the add and the pop fixes this.

Joel C
  • 2,958
  • 2
  • 15
  • 18
  • Thanks, this works perfect, I`m new in assembly language and this was a great help, it took me like one week, but thanks really appreciate it :D – Bit87 Dec 06 '15 at 03:38
  • Glad to help. I don't do much assembly programming myself, but the knowledge certainly helps when debugging C code :) – Joel C Dec 06 '15 at 03:39
0

A few problems, you need to push the "number" not as address, but as numeral.

push dword number

After you call printf, you need to restore the stack, ESP. Basically when you "push" a register, it gets stored in the stack. Since you push twice (two arguments), you need to restore 8 bytes.

When you "pop eax", you're retrieving the top of the stack, which is "number", not the counter. Therefore, you just need to do

pop eax
pop eax

then there is no need to restore the ESP by adding since it is done by popping. Basically, after the first iteration, eax points at an address, so it will never be equal to 10.

Further reading about Stack Pointer and Base Pointer: Ebp, esp and stack frame in assembly with nasm

Community
  • 1
  • 1
Steven
  • 604
  • 6
  • 11
  • `add esp, 4` is preferred (in cases where you don't care about the valus on the stack anymore) to popping since it doesn't require accessing memory like `pop` would, – Michael Petch Dec 06 '15 at 11:14
  • @MichaelPetch: actually, depending on context `add esp, 4` can be slower. The stack engine will have to insert an extra uop to sync the OOO-core's value of `esp` with the stack-engine's offset. `pop` is a single-uop instruction, and load-port resources are usually not a bottleneck. But this answer should have suggested using a [call-preserved register](http://stackoverflow.com/a/34100481/224132) like ebx for a loop variable, instead of eax. – Peter Cordes Dec 06 '15 at 16:37
  • 1
    As for the the comment about using a different register, that part is very true and why I didn't actually upvote this answer. The mess with the extra registers only occurs because we happen to use a register that will be clobbered. Best fix for that is to use a different one. – Michael Petch Dec 06 '15 at 17:03
  • @MichaelPetch: Intel has had a stack-engine since Pentium-M, and AMD since K10. Nobody cares how code will run on irrelevant old CPUs; those cores aren't found anywhere, are they? I mean, there's historical interest, and understanding why old asm made the choices it did. But for telling newbies things they should remember, I try to keep it simple. This is also why I complain about instruction choice on 8086 answers. They're probably never going to optimize for a hardware 8086, so might as well learn idioms that are good on modern hardware. Esp. when both ways are equal on HW 8086. – Peter Cordes Dec 06 '15 at 17:21
  • Sorry, I gave him the answer to pop twice instead of adding 8 to give him a better understanding of how it works. – Steven Dec 07 '15 at 02:20
  • Where I can find references of this `add esp,4`, printf sys calls? – Bit87 Dec 07 '15 at 03:17