Author Topic: NASM error: more than one input file specified  (Read 18234 times)

Offline vjnguyenv

  • Jr. Member
  • *
  • Posts: 5
NASM error: more than one input file specified
« on: March 05, 2012, 03:02:57 AM »
I debugged my program and got the error of "more than one input file specified", but I have no idea what exactly it is. If anyone could help, I would greatly appreciated. Basically I get this weird "e" after i input my first number.

Here's my code: Adding two numbers (display numbers inputted)

Code: [Select]
;32-bit Add Two Numbers

        global _start

        extern stoi

        extern itos

section .data
prompt1  db     "Enter first number: ",0x00
msglen1  equ    $ - prompt1

prompt2  db     "Enter second number: ",0x00
msglen2  equ    $ - prompt2

outmsg1  db     "You entered ",0x00
msglen3  equ    $ - outmsg1

outmsg2  db     " and ",0x00
msglen4  equ    $ - outmsg2

outmsg3  db     ", the sum of these is ",0x00
msglen5  equ    $ - outmsg3

section .bss
number1  resb   20
number2  resb   20
total    resb   20

buffer   resb   20

section .text
_start:                   ; Write a prompt
        mov eax, 4        ; function code for system write
        mov ecx, prompt1  ; address of string to be written
        mov edx, msglen1  ; length of string to be written
        mov ebx, 1        ; file descriptor or device (stdout)
        int 80h           ; generate system call

        mov eax, 3        ; function code for system read
        mov ecx, number1  ; address of string to be read
        mov edx, 18       ; length of buffer (minus a little)
        mov ebx, 0        ; file descriptor or device (stdin)
        int 80h           ; generate system call

        mov eax, number1
        call stoi
        mov [number1], eax

    ; Write a prompt
        mov eax, 4        ; function code for system write
        mov ecx, prompt2  ; address of string to be written
        mov edx, msglen2  ; length of string to be written
        mov ebx, 1        ; file descriptor or device (stdout)
        int 80h           ; generate system call

        mov eax, 3        ; function for system read
        mov ecx, number2  ; address of string to be read
        mov edx, 18       ; length of buffer (minus a little)
        mov ebx, 0        ; file descriptor or device (stdin)
        int 80h           ; generate system call

        mov eax, number2
        call stoi
        mov [number2], eax

        mov eax, 4        ; function code for system write
        mov ecx, outmsg1  ; address of string to be written
        mov edx, msglen3  ; length of string to be written
        mov ebx, 1        ; file descriptor or device (stdout)
        int 80h           ; generate system call

        mov eax, [number1]
        mov ecx, 14
        mov ebx, number1
        call itos

        mov eax, 4
        mov ecx, number1
        mov edx, 19
        mov ebx, 1
        int 80h

        mov eax, 4        ; function code for system write
        mov ecx, outmsg2  ; address of string to be written
        mov edx, msglen4  ; length of string to be written
        mov ebx, 1        ; file descriptor or device (stdout)
        int 80h           ; generate system call

        mov eax, [number2]
        mov ecx, 20
        mov ebx, number2
        call itos

        mov eax, 4
        mov ecx, number2
        mov edx, 19
        mov ebx, 1
        int 80h

    mov eax, [number1]
        add eax, [number2]
        mov [total], eax

        mov ecx, 20
        mov ebx, total
        call itos

        mov eax, 4        ; function code for system write
        mov ecx, outmsg3  ; address of string to be written
        mov edx, msglen5  ; length of string to be written
        mov ebx, 1        ; file descriptor or device (stdout)
        int 80h           ; generate system call

        mov eax, 4
        mov ecx, total
        mov edx, 19
        mov ebx, 1
        int 80h

        mov eax, 1        ; function code for system exit
        mov ebx, 0        ; exit status
        int 80h
« Last Edit: March 05, 2012, 04:29:21 AM by Frank Kotler »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: NASM error: more than one input file specified
« Reply #1 on: March 05, 2012, 05:08:21 AM »
I put "code tags" around your code... the word "code" in brackets ('[]') at the beginning and "/code" at the end. Helps with the "wrap"...

The "more than one input file specified" error is probably due to a typo in your command line. If you can't figure it out, show us exactly what you did... But if you're getting as far as inputting the first number, you must have figured it out...

Where are you getting this "stoi" and "itos" you're apparently linking against? What are the calling conventions? Doesn't look like C...

It looks to me like you're trying to add the two numbers while they're in "string" form. That probably won't work. You may want to use a separate variable for "number1" as a string and "no1" as a number (the latter only needs to be a dword). I don't know if that has anything to do with the "weird e" or not...

You're printing the zero-terminator on your messages. See Bryant's comment in the nearby "calculator" thread. This doesn't do any real harm, but it isn't really "right".

In some cases, you seem to have a mismatch between the "msg" or "prompt" and the length. This probably isn't your current problem, but it could cause some weird results (partial messages being printed or "garbage" after it).

I think I'd suggest separate variables for "number as string" and "number as number" as a first try. I can test this for ya, but I'd need to know about "stoi"/"itos" first...

Best,
Frank


Offline vjnguyenv

  • Jr. Member
  • *
  • Posts: 5
Re: NASM error: more than one input file specified
« Reply #2 on: March 05, 2012, 06:35:27 AM »
Sorry I forgot to put in the code brackets Frank. I am able to run my program. The objective of my program is to get 2 user inputs and display "You enter ___ and ___, the sum of these is ___" I have written the program where I add the two user inputs to display the sum correctly. My problem now that I'm having is that after inputting the numbers it displays "You entered 123È and 456, the sum of these is 6907749" I don't know why there is that "È" after the first input. I was able to get the program to say "You entered 123 and 456" without the "È", but trying to further fulfill the objective I get that weird "È". After debugging I just know it tells me "more than one input file specified". By the way I am linking "stoi" and "itos".

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: NASM error: more than one input file specified
« Reply #3 on: March 05, 2012, 05:15:41 PM »
Yes, I can see that you're linking "stoi" and "itos", but from where? If they're from libc (which I don't think they are), you've got the calling convention wrong! I can "invent" some functions, but they may not do what "your" functions do. In particular, I don't know what ecx does in "itos". Maximum length? Right justified in a field of that length? Or what?

From what I can see, you're inputting a string to "number1", converting it to a number and putting it back into "number1", then converting it back to a string and putting it back into "number1" again. Then the same for "number2". Then you're adding the first four characters of the two strings. This is not going to produce a useful result!

This is a WAG at what I think your code should perhaps look like:

Code: [Select]
;32-bit Add Two Numbers

        global _start

        extern stoi

        extern itos

section .data
prompt1  db     "Enter first number: ",0x00
msglen1  equ    $ - prompt1 - 1

prompt2  db     "Enter second number: ",0x00
msglen2  equ    $ - prompt2 - 1

outmsg1  db     "You entered ",0x00
msglen3  equ    $ - outmsg1 - 1

outmsg2  db     " and ",0x00
msglen4  equ    $ - outmsg2 - 1

outmsg3  db     ", the sum of these is ",0x00
msglen5  equ    $ - outmsg3 - 1

section .bss
number1  resb   20
no1 resd 1
number2  resb   20
no2 resd 1
total    resb   20
tot resd 1

buffer   resb   20

section .text
_start:
nop ; for gdb
                   ; Write a prompt
        mov eax, 4        ; function code for system write
        mov ecx, prompt1  ; address of string to be written
        mov edx, msglen1  ; length of string to be written
        mov ebx, 1        ; file descriptor or device (stdout)
        int 80h           ; generate system call

        mov eax, 3        ; function code for system read
        mov ecx, number1  ; address of string to be read
        mov edx, 18       ; length of buffer (minus a little)
        mov ebx, 0        ; file descriptor or device (stdin)
        int 80h           ; generate system call

        mov eax, number1
        call stoi
        mov [no1], eax

    ; Write a prompt
        mov eax, 4        ; function code for system write
        mov ecx, prompt2  ; address of string to be written
        mov edx, msglen2  ; length of string to be written
        mov ebx, 1        ; file descriptor or device (stdout)
        int 80h           ; generate system call

        mov eax, 3        ; function for system read
        mov ecx, number2  ; address of string to be read
        mov edx, 18       ; length of buffer (minus a little)
        mov ebx, 0        ; file descriptor or device (stdin)
        int 80h           ; generate system call

        mov eax, number2
        call stoi
        mov [no2], eax

        mov eax, 4        ; function code for system write
        mov ecx, outmsg1  ; address of string to be written
        mov edx, msglen3  ; length of string to be written
        mov ebx, 1        ; file descriptor or device (stdout)
        int 80h           ; generate system call

        mov eax, [no1]
        mov ecx, 14
        mov ebx, number1
        call itos

        mov eax, 4
        mov ecx, number1
        mov edx, 19
        mov ebx, 1
        int 80h

        mov eax, 4        ; function code for system write
        mov ecx, outmsg2  ; address of string to be written
        mov edx, msglen4  ; length of string to be written
        mov ebx, 1        ; file descriptor or device (stdout)
        int 80h           ; generate system call

        mov eax, [no2]
        mov ecx, 20
        mov ebx, number2
        call itos

        mov eax, 4
        mov ecx, number2
        mov edx, 19
        mov ebx, 1
        int 80h

    mov eax, [no1]
        add eax, [no2]
        mov [tot], eax

        mov ecx, 20
        mov ebx, total
        call itos

        mov eax, 4        ; function code for system write
        mov ecx, outmsg3  ; address of string to be written
        mov edx, msglen5  ; length of string to be written
        mov ebx, 1        ; file descriptor or device (stdout)
        int 80h           ; generate system call

        mov eax, 4
        mov ecx, total
        mov edx, 19
        mov ebx, 1
        int 80h

        mov eax, 1        ; function code for system exit
        mov ebx, 0        ; exit status
        int 80h

This is untested, and probably still has errors! In particular, the length that you're writing probably doesn't match the length of anything meaningful you've got in the buffers (depending on what "itos" does with ecx). It may get you closer...

I'm not able to understand what you're telling me about the "more than one input file" message. After you debug it? Doesn't make any sense! What app is giving you this message? The debugger? Nasm? I'm lost!

I may try to invent plausible "stoi" and "itos" functions to try... later. Better if you tell me what you're using - link or post 'em here. Until then...

Best,
Frank


Offline vjnguyenv

  • Jr. Member
  • *
  • Posts: 5
Re: NASM error: more than one input file specified
« Reply #4 on: March 05, 2012, 11:03:26 PM »
This is how I get the "stoi" and "itos" fromt he code below, I just know how to link it from my teacher. I just started assembly language. I think i'm using NASM to debug as this is what i type to debug "nasm -g elf SumOfTwoNum.asm" and after that I get the error "nasm: error: more than one input file specified
type `nasm -h' for help"


Code: [Select]
segment .bss
inBufferAddr:
        resd    1               ; address of input buffer
inBufferEnd:
        resd    1               ; length of input buffer

newLine equ     0xa
asc0    equ     "0"
decBase equ     10

segment .code
        global  stoi
stoi   mov     esi, eax        ; convert string to integer, addr. in eax
        sub      eax, eax        ; string must end w/ new line
        mov     ecx, decBase    ; we will divide by 10 until done
stoiNxt:
        sub      bl, bl          ; clear bl
        mov     bl, [esi]       ; get next char
        cmp     bl, newLine     ; last char.?
        je       stoiDone        ; exit
        sub     bl, asc0        ; convert to digit
        mul     ecx             ; multiply present value by base
        add     eax, ebx        ; add next digit
  inc      esi             ; incr. source pointer
        jmp     stoiNxt         ; loop until new line

stoiDone:
        ret

        global  itos
itos   mov    [inBufferAddr], ebx     ; convert int. (in eax) to str.
        mov    edi, ebx                ; buffer addr. in ebx, move to edi
        add     edi, ecx                ; length in ecx, add to addr. to get end
        mov    [inBufferEnd], edi      ; save buffer end (+1)
        dec     edi
        mov     bl, 0                   ; end string w/ zero
        mov    [edi], bl
        dec     ecx
        mov    ebx, decBase
itosNxt:
        sub     edx, edx                ; clear dx
  div      ebx                     ; divide by base
        add     dl, asc0                ; convert digit to ASCII
        dec     edi                     ; decr. string array ptr.
        mov    [edi], dl               ; save next digit in string
        cmp    eax, 0                  ; check for zero quotient
        je       itosDone                ; if so, conversion complete
        loop    itosNxt                 ; if not, process next digit
itosDone:                               ; shift buffer left if necessary
        mov     ecx, [inBufferEnd]      ; get buffer end addr.
        sub      ecx, [inBufferAddr]     ; subtract beginning addr.
        mov     esi, edi                ; get addr. of last char. processed
        mov     edi, [inBufferAddr]     ; set dest. to beginning of buffer
nxtChar:
        cld
;       mov     bl, [esi]               ; get leftmost char of string
;       mov     [edi], bl               ; move to beg. of buffer
;       inc     esi                     ; incr. both pointers
;       inc     edi
;       loop    nxtChar                 ; loop until done
        rep movsb
        mov     [edi], byte 0           ; terminate string with zero
notZero mov     eax, [inBufferAddr]     ; return beginning of buffer
        ret

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: NASM error: more than one input file specified
« Reply #5 on: March 06, 2012, 01:51:36 AM »
Okay, that clears things up! First, the subject of this thread...
Quote
I think i'm using NASM to debug as this is what i type to debug "nasm -g elf SumOfTwoNum.asm"
You're not using Nasm to debug anything - it's not capable! What the "-g" switch does is to add debugging information to your code for the use of some other debugger - probably gdb... but there are others. The "-g" switch doesn't take any parameters, so Nasm thinks "elf" is a filename, thus the error. The "-f" switch tells Nasm which output format we want, and it does take a parameter - in this case we want "elf" (or "elf32" does the same thing). So what you want, to assemble into "-f elf" format, with debugging information, is:
Code: [Select]
nasm -g -f elf SumOfTwoNum.asm
This may not be ideal. "-g" emits debugging info in the default format, which for Nasm is called "stabs". gdb actually prefers a different format, called "dwarf". We can specify this with the "-F" (uppercase!) switch, so...
Code: [Select]
nasm -F dwarf -f elf SumOfTwoNum.asm
might be better. You may have noticed that one of the changes I made to your code was to add a "nop" right after the "_start:" label - that's for gdb, too. It's happier with a single-byte opcode in first place. If you're not actually using a debugger, you don't need to worry about any of this.

The other thing is that "itos" creates a zero-terminated string. It would work fine if you were printing it with printf or puts, but sys_write doesn't know about zero-terminated strings - it prints as many characters as are in edx, including any "garbage" that follows what we want to print. It might be more useful if "itos" returned the length, instead of the address of the buffer (which we knew - it was in ebx). Since it doesn't, we're going to have to calculate the length to tell sys_write. The "usual" way would be to call strlen(), but we can easily do it ourselves, and have it in edx where we want it!
Code: [Select]
mov ecx, number1
xor edx, edx ; or sub edx, edx ... start with zero
getlen:
cmp byte [ecx + edx], 0
jz gotlen
inc edx
jmp getlen
gotlen:
; now the length is in edx
mov ebx, 1
mov eax, 4
int 80h
Since you're doing this several times, you're going to have to make up some new names for the labels - getlen2/gotlen2 etc. or whatever - make sure to make 'em match! Since you're doing it several times, you might want to make this a subroutine, but it may be easier to make up some new names, for now.

With those hints, you can probably get something that works with no error messages and no weird characters. Get back to us if you still have trouble.

Maybe I shouldn't mention this - I have an idea it's your teacher's code, not yours - but there's a bug in "stoi"! You're not seeing it, 'cause you always put 0 (stdin) or 1 (stdout) in ebx. To trigger it, put some value greater than 100h in ebx before calling stoi. I think you'll find you get the wrong result. To fix it:
Code: [Select]
stoiNxt:
;       sub bl, bl
        sub ebx, ebx ; clear ALL of ebx
...

Best,
Frank


Offline vjnguyenv

  • Jr. Member
  • *
  • Posts: 5
Re: NASM error: more than one input file specified
« Reply #6 on: March 06, 2012, 02:12:13 AM »
It is the teacher's code, he told us to use it for our program. Some of what you just mention, our teacher hasn't even mention about cmp which I know is something for comparing and others that you wrote, I still have no idea, I'm guessing we're not that far yet. So far it's just print a string, read an input, add the two numbers, that's all I know. My first program that I did was to get just 2 user inputs and get the sum, that was successful, now teacher wants us to print the inputted numbers along with the total, thats where I get the weird error, but noticing only in the first input. So then I decided to just write a code where it just tells me what I entered, which didn't have any errors or that weird "E" after the first input, so then I just added to that code the Addition part and then it just messes up.

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: NASM error: more than one input file specified
« Reply #7 on: March 06, 2012, 05:17:40 AM »
Well, here's another way we might tell sys_write how many bytes (characters) we want to print. When we do the sys_read to get the user's input, it returns the number of characters entered in eax. This includes the linefeed - 0xA - generated when the user hits the "enter" key (sys_read won't return without it!) - we probably don't want to count that as part of the length to print. (in this case, anyway)...

You already let Nasm calculate the lengths of your prompts, like:
Code: [Select]
msg db "blahblahblah"
msg_len equ $ - msg
(you actually zero-terminate your strings - see Bryant's comment in the "calculator" thread - and I subtracted it in my "version" of your code)
"msg_len" is a "constant", and we use it like this:
Code: [Select]
mov edx, msg_len ; length
mov ecx, msg ; address
...
Since we don't know the length of the input in advance, this is going to have to be a "variable":
Code: [Select]
number1 resb 20 ; reserve 20 bytes
number1_len resd 1 ; reserve 1 dword (4 bytes)
Then we do our sys_read...
Code: [Select]
mov edx, 20 ; maximum to get
mov ecx, number1 ; address to put it
mov ebx, 0 ; stdin
mov eax, 3
int 80h
dec eax ; we don't want the LF
mov [number1_len], eax ; save the length
...

Then when it comes time for the sys_write, we want the "[contents]" of the variable in edx...

Code: [Select]
mov edx, [number1_len]
mov ecx, number1
mov ebx, 1
mov eax, 4
int 80h
You see the difference between "mov edx, foo" and "mov edx, [foo]", right? It's an important concept to get!

This can potentially tell us how long "number1" and "number2" are... we've still got to figure out the length of "total" (expressed as a string)...

You don't know "cmp" (yet). Have you learned "sub"? "cmp" does the same thing as "sub", except that it doesn't store the results, it just sets the flags as if the "sub" happened. Have ya got to "flags" yet? Maybe not... In the flags register, each bit has a special meaning, some of which can be useful to us. Certain instructions - the "conditional jumps" - behave differently, depending on the condition of certain bits in the flags register. For example:
Code: [Select]
; address of "number1" in ecx - as sys_write wants
mov ecx, number1
;xor edx, edx ; or sub edx, edx ... start with zero
mov edx, 0 ; even clearer to the beginner :)

getlen:
; compare contents of ["number1" plus edx] to zero
cmp byte [ecx + edx], 0
; flags set per "cmp"
; we're interested in the zero-flag
; it will be set if the two values are equal
; (result of a "sub" would be zero)
; if zero-flag is set, "jz" jumps to the specified label
; if not, it falls through to the next instruction
; "je" (jump if equal) is another name for "jz"
; perhaps it would be clearer...
;jz gotlen
je gotlen
; if it's not the byte we're looking for...
inc edx ; advance to the next byte/char
jmp getlen ; and go check it

gotlen: ; we found the terminating zero
; now the length is in edx
mov ebx, 1 ; stdout
mov eax, 4 ; sys_write
int 80h
Something like that...

In the code you showed, you used the same buffer for "number1 as a number" and "number1 as a string". You could probably get it to work like that (if you want to), but you'll have to rearrange it a little. When you get the input, it's as a string - no choice about that. Then you convert it to a number - suitable to add. But then you convert it back to a string before doing the "add". When you do the "add", both numbers need to be in the form of numbers - adding parts of two strings together won't give you the result you want, trust me! Save the "total" (as a number, at this point), then you can convert all three numbers back to a string, just before you display 'em. "total" has to be converted to a string, of course, but we had the other two numbers as strings, before we overwrote 'em. I think it's easier to use a separate variable for "number as number". Gives the teacher's code a good workout, anyway. :)

Best,
Frank



Offline vjnguyenv

  • Jr. Member
  • *
  • Posts: 5
Re: NASM error: more than one input file specified
« Reply #8 on: March 07, 2012, 06:53:51 AM »
I got my program to run correctly today. I thank you for the help Frank