Author Topic: imul, printf doesn't work with my code  (Read 11139 times)

Offline melviii100

  • Jr. Member
  • *
  • Posts: 8
imul, printf doesn't work with my code
« on: June 07, 2014, 11:57:32 AM »
am using ubuntu 14.10 64 bit.

am trying to read a number, square it, and print. when i run i face following probs
1) before it print "enter a number : "  system waits for input !
2) after find out square it prints -  "square of input is : 6806881". what is the problem in my code?

code:
Code: [Select]
bits 32
extern printf
extern scanf

segment .data
prompt1 db "enter a number : ", 0
sqr_msg db "square of input is : %d",10, 0


segment .bss
input1 resd 1
segment .text
global main
main:

push prompt1
call printf
add esp, 4

mov eax, 3
mov ebx, 2
mov ecx, input1
mov edx, 2
int 80h

mov eax, [input1]
imul eax
mov ebx, eax

push ebx
push sqr_msg
call printf
add esp, 8

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: imul, printf doesn't work with my code
« Reply #1 on: June 07, 2014, 10:16:49 PM »
You'll have to pardon me. I just said the other day, "I may be back to a 32-bit system soon." Sure enough, my "new" computer just died (power supply, I think) so I'm back to my (very) old computer. I'm in a bit of a mess.

1) Printf's dirty little secret is that it doesn't print anything until the buffer is flushed. Easy way is just to put a linefeed at the end of your prompt "...", 10, 0". Yeah, you probably wanted input on the same line as the prompt. Tough! Or you could explicitly flush() stdout. Or you could use scanf (or other high-level input) instead of the low-level sys_read like you're doing. The man pages explicitly advise against mixing high and low level I/O. You've got scanf declared as extern, might as well use it. Scanf takes the address of an integer, not the integer itself as a parameter. Obvious, if you think about it, but K&R calls this "the most common error". Don't make it.

2) sys_read reads characters not numbers. Well, they're numbers, but the ascii codes of characters. If  you type "123" you'll have 31h 32h 33h in your input buffer. The number you're displaying is, no doubt, the square of this. To do arithmetic (successfully) you need to convert from characters to a number. Scanf does this for you... and will flush the output from printf as a bonus. This is probably your best bet.

We can show you how to convert characters to number and number to characters (you'll need both) if you want to use sys_read and sys_write, too. I break down and use scanf/printf for floats (printf always wants doubles!), but integers are easy(?).

Scanf is probably your best bet here. Get back to us if you have further trouble.

(just a thought: a square will always be positive, so you might want "%u" rather than "%d")

Best,
Frank


Offline melviii100

  • Jr. Member
  • *
  • Posts: 8
Re: imul, printf doesn't work with my code
« Reply #2 on: June 08, 2014, 05:06:58 AM »
when i tried with scanf it's worked. but actually i posted a portion of my program. my real program starts from a c code, which calls the asm function "asm_main".
so i complied it with gcc.
now i avoided the C code, and tried following commands,
Code: [Select]
$nasm -f elf32 math.asm
$ld -m elf_i386 -s -o math math.o

got error:
Code: [Select]
ld: warning: cannot find entry symbol _start; defaulting to 0000000008048080
math.o: In function `main':
math.asm:(.text+0xb): undefined reference to `printf'
math.asm:(.text+0x1d): undefined reference to `scanf'
math.asm:(.text+0x32): undefined reference to `printf'

2nd problem,(compile with gcc, function call from C)
tried to read without scanf. and square it.
Code: [Select]
mov eax, 3
mov ebx,0
mov ecx, input2
mov edx, 2
int 80h

       mov eax, [input2]
sub eax, '0'   ; convert ascii to decimal
imul eax
add eax, '0'   ;convert decimal to ascii
push eax
push sqr_msg
call printf
add esp, 8

output: square of input is : 6563892

what is the problem in my code?

and can you explain the concept "add esp, 8". i used "push eax" so don't i need to use "pop eax" ?

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: imul, printf doesn't work with my code
« Reply #3 on: June 08, 2014, 08:16:46 AM »
Code: [Select]
mov eax, 3 ; sys_read
mov ebx,0 ; stdin
mov ecx, input2
mov edx, 2 ; one digit and the linefeed
int 80h

       mov eax, [input2] ; one digit and the linefeed
;    xor eax,eax ; make sure upper bytes are clear
;    mov al, [input2]
; or
;    movzx eax, byte [input2]
; does the same thing

sub eax, '0'   ; convert ascii to decimal
imul eax ; do you really want imul? result might be negative?
add eax, '0'   ;convert decimal to ascii ; (for printf)?
push eax
push sqr_msg
call printf
add esp, 8

Suppose you type "5" (enter). What goes in your buffer is 35h 0Ah. On x86, multi-byte numbers are stored little endian. So when you do "mov eax, [input2]" eax is 00000A35h. If there was cruft after input2, the upper bytes might not be zero. You subtract '0', so 0A05h (at least). Squaring that does not give the number you mention, so I deduce you did not type "5"... but it's close.

If you typed anything greater than "3", it'll be two digits, so adding '0' may not cover it. Since you're passing this squared number to printf, which does the "number to ascii" for you, you don't want to do that anyway.

You could "pop eax" (twice) if you wanted to get your number back. C functions return their value in eax. The return value from printf isn't usually interesting  but sometimes it is. You might want to check the return value from scanf, for example, to make sure the user hasn't entered garbage. It is usual to "remove" the parameters from the stack by adding to esp, but you can pop if you want to.

If you're going to link this with ld (which I do not particularly recommend) you'll need to tell ld where to find the correct interpreter /dynamic linker - this is what your executable uses to find and load libc- (-I/lib/ld-linux.so.2 on my system - again) and you'll have to tell ld "-lc" so it knows where to look for scanf and printf.

Easier, perhaps, to...
Code: [Select]
nasm -f elf32 math.asm
gcc -m32 driver.c math.o -o math
gcc knows what to tell ld.

You can make it a freestanding program, but you'll need to provide an exit... and an entrypoint. I ASSume that "asm_main" comes with a prolog and epilog.

Best,
Frank