Code:
section .bss
    username:  resb 128                ; Declare username input
    usernameInputSize: resb 4          ; Declare username input size

    password:  resb 128                ; Declare password input
    passwordInputSize: resb 4          ; Declare password input size

section .data
    usernameText: db "Username: "        ; Declare the text Username variable
    usernameTextSize: equ $-usernameText ; Length of usernameText
   
    passwordText: db "Password: "        ; Declare the text Password variable
    passwordTextSize: equ $-passwordText ; Length of passwordText

section .text
     global _start

_start:
     mov eax, 3            ; The system call for read (sys_read)
     mov ebx, 0            ; File descriptor 0 - standard input
     mov ecx, username     ; Variable where input is saved
     mov edx, 128          ; Length in bytes of the input
     int 80h
     mov [usernameInputSize], eax

     mov eax, 3            ; The system call for read (sys_read)
     mov ebx, 0            ; File descriptor 0 - standard input
     mov ecx, password     ; Variable where input is saved
     mov edx, 128          ; Length in bytes of the input
     int 80h
     mov [passwordInputSize], eax
     
     mov eax, 4                 ; The system call for write (sys_write)
     mov ebx,1                  ; File descriptor 1 - standard output
     mov ecx, usernameText      ; Save the variable to write in ecx
     mov edx, usernameTextSize  ; Length in bytes of the output
     int 80h
     
     mov eax, 4            ; The system call for write (sys_write)
     mov ebx, 1            ; File descriptor 1 - standard output
     mov ecx, username     ; Save the variable to write in ecx
     mov edx, [usernameInputSize]
     int 80h
     
     mov eax, 4                 ; The system call for write (sys_write)
     mov ebx,1                  ; File descriptor 1 - standard output
     mov ecx, passwordText      ; Save the variable to write in ecx
     mov edx, passwordTextSize  ; Length in bytes of the output
     int 80h
     
     mov eax, 4            ; The system call for write (sys_write)
     mov ebx, 1            ; File descriptor 1 - standard output
     mov ecx, password     ; Save the variable to write in ecx
     mov edx, [passwordInputSize]
     int 80h

     mov eax, 1            ; The system call for exit (sys_exit)
     mov ebx, 0            ; Exit with return code of 0 (no error)
     int 80h               ; Exit program


I managed to use variables now. I think the next thing I wanna code is something related to time, I found some linux system calls for it.

Do you think it's a good idea or I should try something else now?

Thanks Smile

Also, @Kerm: Writing x86 ASM on the 8th grade? wow...
KermMartian wrote:
Qwerty.55 wrote:
It's a pity the OS doesn't let you get close enough to the hardware to talk to the screen driver... Sad
Back in 8th grade when I was writing x86 ASM, I remember that you could at least full-screen the command window and address characters, setting the background color, foreground color, and character, for pretty fun and nifty graphics.

If you go to Ben Ryves' website, he has a tutorial to do it in C, but the concepts should still apply to z80. That was a fun week of trying to figure stuff out with it Razz
ephan wrote:
I managed to use variables now. I think the next thing I wanna code is something related to time, I found some linux system calls for it.

Do you think it's a good idea or I should try something else now?

Thanks Smile

Also, @Kerm: Writing x86 ASM on the 8th grade? wow...


If you really want to continue with x86, you should actually learn C first. Many of the concepts you are struggling with are not related to assembly, but are just low level issues. Go learn those in an easier language, then revisit x86 assembly in ~3-6 months when you have a decent grasp of C.
I actually started learning ASM to understand C better.

I thought like this:

I am not used to low level.
I can't get used to C.
Let's get used to ASM so that then C looks easy and high-level.
ephan wrote:
I actually started learning ASM to understand C better.

I thought like this:

I am not used to low level.
I can't get used to C.
Let's get used to ASM so that then C looks easy and high-level.


Yeah, that thought process doesn't work :p

For programming, you should start high level and work your way downward. Start with something like Python (or maybe C#/Java), then move on to C/C++. Then, once you are intimately familiar with C/C++, move on to assembly if you want.
Kllrnohj wrote:
ephan wrote:
I actually started learning ASM to understand C better.

I thought like this:

I am not used to low level.
I can't get used to C.
Let's get used to ASM so that then C looks easy and high-level.


Yeah, that thought process doesn't work :p

For programming, you should start high level and work your way downward. Start with something like Python (or maybe C#/Java), then move on to C/C++. Then, once you are intimately familiar with C/C++, move on to assembly if you want.


I'd disagree. Many of the constructs that are useful in Python and other higher level languages simply don't exist in ASM. Attempting to think like that is almost certainly going to result in inefficient and convoluted code for the sole reason that you're thinking outside of the language's paradigm. That said, ASM (particularly x86-64) is much more difficult than C. If you're struggling to learn C without already knowing ASM, it'd be much more worthwhile to learn a similar language like C++ or D than ASM. ASM has most of the problems of C with the addition that you have to know how to solve *everything*. There's no compiler to fill in the gaps. For your case, the only advantage of ASM would be that the instruction set is a bit simpler than that of C.
Qwerty.55 wrote:
I'd disagree. Many of the constructs that are useful in Python and other higher level languages simply don't exist in ASM.


Irrelevant. The point is to learn the *concepts*. Things like algorithms, code structure, sanitizing inputs, debugging, etc... are very similar between languages.

Code:
section .data
  x: db 5
  txt: db "X is 5"
  txtLen: equ $-txt

section .text
  global _start

_start:
  mov eax, $x
  cmp eax, 5
  jne end                         ;If not equal to 5, jump to end
 
  ;If eax is 5, display some text
  mov eax, 4
  mov ebx, 1
  mov ecx, txt
  mov edx, txtLen
  int 80h
 
end:
  inc eax
 
  mov eax, 1                      ; The system call for exit (sys_exit)
  mov ebx, 0                      ; Exit with return code of 0 (no error)
  int 80h                         ; Exit program


I think the comments speak for the code, but for some reason I am trying to compare x (moved to eax) with 5 (and x is 5) and I don't get the output.

Basically, in C it'd be:


Code:

int main()
{
  int x = 5;
  if ( x== 5)
  {
    printf("X is 5");
  }
  return 0;
}


Thanks for the help, I just can't see what's wrong.
What does the $ in front of the x mean? Doesn't NASM use [] to dereference a pointer?

My guess for why it isn't working is that you are loading 4 bytes into the register instead of just the 1 byte you defined x as. I think it should be "mov BYTE eax, [x]", but I'm not entirely sure. Alternatively, use "x: dd 5" instead of "x: db 5"
Kllrnohj wrote:
What does the $ in front of the x mean? Doesn't NASM use [] to dereference a pointer?

My guess for why it isn't working is that you are loading 4 bytes into the register instead of just the 1 byte you defined x as. I think it should be "mov BYTE eax, [x]", but I'm not entirely sure. Alternatively, use "x: dd 5" instead of "x: db 5"


Indeed, [] is NASM's dereferencer.

I changed variable x's declarator from "db" to "dd" and it worked:


Code:

section .data
  x: dd 5
  txt: db "X is 5"
  txtLen: equ $-txt

section .text
  global _start

_start:
  mov eax, [x]
  cmp eax, 5
  jne end                         ;If not equal to 5, jump to end
 
  ;If eax is 5, display some text
  mov eax, 4
  mov ebx, 1
  mov ecx, txt
  mov edx, txtLen
  int 80h
 
end:
  inc eax
 
  mov eax, 1                      ; The system call for exit (sys_exit)
  mov ebx, 0                      ; Exit with return code of 0 (no error)
  int 80h                         ; Exit program


I wondered what "dd" meant:

Quote:
The DD statement initializes memory with one or more 32-bit double word values. label is a symbol that is assigned the current memory address. expression is a double word value that is stored in memory. Each expression may be a symbol, a string, or an expression.


But I still don't quite get it.
dd is just a different way to declare bytes. In z80 ASM, you can use db for one byte, or dw for a word. In x86 ASM, it seems that you have db (byte) and dd (4 bytes, 32 bits, an int), as well as some in between, I would think. You use it the same way that you use db, but now you use the $ operator to get the values (which pulls in 4 bytes, it seems) instead of the [] operator, which only gets one byte.
ephan wrote:
But I still don't quite get it.


I'm not sure what $ means in NASM, but a couple of things could have been going wrong. Either

A) You weren't derefencing the pointer, meaning you were storing the value of the pointer, NOT the value pointed to by the pointer. Eg, you were doing this:


Code:
int _data = 5;
int *x = &_data;

if (x == 5) // should be if (*x == 5)


You could also declare the label as a value instead of a pointer, but I'm not 100% sure how to do that. I think you use equ to do that, same as you do for txtLen

B) You were reading 4 bytes from x, but only specifying 1 byte for x. You were thus picking up 3 "garbage" bytes from around x. mov defaults to reading the size of the register. You gave it a 32-bit register, so it tried reading 32-bits from the source. You can specify the size if you want: "mov BYTE eax, [x]" or "mov WORD eax, [x]" (for 1 byte and 2 bytes, respectively)

_player1537 wrote:
You use it the same way that you use db, but now you use the $ operator to get the values (which pulls in 4 bytes, it seems) instead of the [] operator, which only gets one byte.


No. In NASM labels are always pointers. You use [] to get the value at the pointer. [] implies nothing about the size or what is at the pointer. If he wanted to just use a single byte, he needs to alter the mov command to read just one byte (eg, "mov BYTE eax, [x]")
Thanks Kllrnohj and player1537.

I managed to do it all and understand it.

Now I get to one of the most complicated (I think) things, which is to:
- Get integer input, or convent strings to integers and integers to strings.
ephan wrote:
Now I get to one of the most complicated (I think) things, which is to:
- Get integer input, or convent strings to integers and integers to strings.

Those are actually pretty simple.

To convert a string to an integer in C, do something like this (not tested):

Code:
int atoi(char *str)
{
   int n = 0;
   while (isdigit(*str))
      n = 10*n + (*str - '0');
   return n;
}

There's a lot of room for improvement. For example, it doesn't handle negatives or whitespace characters preceding the number. The isdigit() function/macro returns non-zero if the character is a digit between '0' and '9'. You can also write that test as ('0' <= *str && *str <= '9').

To convert an integer to a string, do the same thing in reverse:

Code:
char *itoa(int n)
{
   static char str[11]; // large enough for 32-bit number plus a null terminator
   char *s = &str[10]; // start at the end of the string
   *s = '\0'; // terminate it
   do {
      *--s = (n % 10) + '0';
      n /= 10;
   } while (n > 0);
   return s; // return the string
}

Again, this code is not tested, and it's limited to positive integers. Also, it is not re-entrant because it overwrites a static string buffer (str).

Have fun writing it in x86. Smile
Why can't I use pop and push in x86-64?


Code:
  mov eax, 0
Beginning:
  inc eax

  push eax

  mov eax, 4                 ; The system call for write (sys_write)
  mov ebx, 1                 ; File descriptor 1 - standard output
  mov ecx, inputText         ; Save the variable to write in ecx
  mov edx, [inputTextSize]   ; Length in bytes of the output
  int 80h

  pop eax
  cmp eax, 0x0A
  jne Beginning


I was trying that loop to output the input 10 times.

reverser.asm:26: error: instruction not supported in 64-bit mode

But I get that for both push and pop.

Thanks in advance!
If I'm wrong, I'm sorry, but the problem seems to be that you are trying to push and pop a register that is not 64 bits wide. I think that rax is the 64-bit extension of eax.
Thanks calcdude, that makes sense.


Code:
section .bss
  inputText:  resb 128                 ; Declare input
  inputTextSize: resb 4                ; Declare input size

section .text
  global _start

_start:
  mov eax, 3                           ; The system call for read (sys_read)
  mov ebx, 0                           ; File descriptor 0 - standard input
  mov ecx, inputText                   ; Variable where input is saved
  mov edx, 128                         ; Length in bytes of the input
  int 80h
  mov [inputTextSize], eax


  dec eax                    ; Iterator equals to string length -1
Beginning:
  dec eax                    ; Iterator--

  mov ecx, inputText         ; Save the variable to write in ecx
  add ecx, eax

  push rax                   ; Save eax, because it is the iterator
  mov eax, 4                 ; The system call for write (sys_write)
  mov edx, 1                 ; Length in bytes of the output
  int 80h

  pop rax                    ; Get eax back
  cmp eax, 0                 ; Compare it to 0...
  jne Beginning              ; ...if not 0, go back to beginning of loop


  mov eax, 1            ; The system call for exit (sys_exit)
  mov ebx, 0            ; Exit with return code of 0 (no error)
  int 80h               ; Exit program


That's a simple ASM program I made just right now, in response to Adriweb's challenge, a "String Reverser" in Assembly.

It was actually very simple, what do you think?
Very nice, and very simple. This is something I bug my ASM coders to do; I think the stack manipulation is easier to see if you indent one more per push and de-indent on each pop. You only use the stack once, though, so it's not a big deal here.
Quote:
my ASM coders


Do you have an army of them? Wink

Well, my code has some stuff that I don't need like inputTextSize, but I left them because they can come in handy:


Code:
section .bss
  inputText:  resb 128                 ; Declare input
  inputTextSize: resb 4                ; Declare input size

section .text
  global _start

_start:
  mov eax, 3                           ; The system call for read (sys_read)
  mov ebx, 0                           ; File descriptor 0 - standard input
  mov ecx, inputText                   ; Variable where input is saved
  mov edx, 128                         ; Length in bytes of the input
  int 80h                              ; Get the input
  mov [inputTextSize], eax             ; Save the size of the input

  dec eax                    ; Iterator equals to string length -1
Beginning:
  dec eax                    ; Iterator--

  mov ecx, inputText         ; Save the variable to write in ecx
  add ecx, eax               ; Index of the character

  push rax                   ; Save eax, because it is the iterator
    mov eax, 4                 ; The system call for write (sys_write)
    mov edx, 1                 ; Length in bytes of the output (character)
    int 80h                    ; Display hte character
  pop rax                    ; Get eax back

  cmp eax, 0                 ; Compare it to 0...
  jne Beginning              ; ...if not 0, go back to beginning of loop


  mov eax, 1            ; The system call for exit (sys_exit)
  mov ebx, 0            ; Exit with return code of 0 (no error)
  int 80h               ; Exit program


What I wanted to do was to save the reserved string in another string, so instead of display every character, I added it to another string, but I don't quite see how to do it.
Just for kicks, I implemented something similar to your earlier snippet. I think it's a somewhat more elegant approach, although the speed suffers since I'm doing lots of little calls to read(). On the other hand, my version doesn't have a fixed acceptable string length, instead limited only by available stack space.

Performance could probably be improved appreciably by aligning the stack to an 8 or 16-byte boundary before invoking syscalls, but meh. It seems to work as-is, anyway.


Code:
section .text

global _start
_start:
;    push ebp       ; Removed since there's no calling stack frame
    mov ebp, esp

read:
    dec esp
    mov eax, 3
    mov ebx, 0
    mov ecx, esp
    mov edx, 1
    int 80h         ; read(stdin, esp, 1)
; EOF?
    cmp eax, 0
    jne read

eof:
    inc esp         ; Correct one-off since we didn't fill that byte
    mov eax, 4
    mov ebx, 1
    mov ecx, esp
    mov edx, ebp
    sub edx, ecx
    int 80h         ; write(stdout, esp, ebp-esp)

    mov eax, 1
    mov ebx, 0
    int 80h         ; exit(0)


Code:
$ nasm -f elf32 rev.S && ld -o rev rev.o
$ echo -ne "\nViet nom nom nom" | ./rev
mon mon mon teiV
$


As for your immediately preceding question, I can't tell what you're trying to do. Care to clarify?
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 4 of 5
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement