Int 80h is basically the entry point to most syscalls available. When you call it, you're actually telling the processor that it's going to use a syscall. Which syscall is used depends on the value in eax. That's why using mov eax,4 is important. As for the other registers, I'm going to say that they're arguments, but since I've never written a line of x86 in my life... Razz
I'm pretty sure it just calls whatever system call you have indicated in registers. For instance, if you used something besides 4 for the mov eax,4, you would be calling a different system call. To put it in z80 terms, you only have one rst call for bcalls, yet you can call whatever one you want.
Code:
bcall $1234 == rst 28h \ .dw $1234
That number tells the rst routine what you want to call, the same is true about int 80h.
No, int 80h IS the system call. Doing the mov's beforehand is the setup for the system call. Leaving out int 80h is like leaving out bcall(_Vputs), and your mov's are like ld hl,TextToPrint.

Edit: Didn't see this page before I posted. The "no" was at David. Smile
I got it, that's where it is different from Z80, but I can still specify which system call I want with register eax right?


Code:
section .data
   hello:     db 'Hello',10           ; 'Hello' plus a linefeed character
   helloLen:  equ $-hello             ; Length of the 'Hello' string
   
   bye:       db 'Goodbye',10         ; 'Goodbye' plus a linefeed character
   byeLen:    equ $-bye               ; Length of 'Goodbye' string
   
section .text
   global _start

_start:
   mov eax,4            ; The system call for write (sys_write)
   mov ebx,1            ; File descriptor 1 - standard output
   
   mov ecx,hello        ; Move the string 'Hello' to ecx to be printed
   mov edx,helloLen     ; Move the length of 'Hello' to edx to be printed
   
    int 80h              ; Display Hello
   
    mov eax,4            ; The system call for write (sys_write)
   mov ebx,1            ; File descriptor 1 - standard output
   
    mov ecx,bye          ; Move the string 'Goodbye' to ecx to be printed
    mov edx,byeLen       ; Move the length of goodbye to edx to be printed
   
    int 80h              ; Display Goodbye
   
   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


My latest program, working.

On a side note, this is the code I use to compile.

Code:
nasm -f elf64 -g -F stabs hello.asm
ld -o hello hello.o
./hello
Bump?
Whatever tutorial your were reading covered other system calls, I would think. Have you read that entire tutorial?
ephan wrote:
Bump?


What's your question, I'm not really seeing one?

Although I do like that Kerm hasn't manned up and apologized to me yet Wink
Agreed, I see no question here.

Referring to whatever ABI documentation there is is frequently useful, though. Here's the System V ABI for AMD64 for example, which mentions how to use system calls on Linux in Appendix A (incidentally, it says to use the C library). When in doubt, ask a C compiler since it probably provides the best reference (I don't think syscall conventions are really documented anywhere, but there may be some system header designed for the C library). There might be something interesting in the kernel source tree's 'doc' directory as well.
ephan wrote:
I got it, that's where it is different from Z80, but I can still specify which system call I want with register eax right?


Code:
section .data
   hello:     db 'Hello',10           ; 'Hello' plus a linefeed character
   0x5:  equ $-hello             ; Length of the 'Hello' string
   
   bye:       db 'Goodbye',10         ; 'Goodbye' plus a linefeed character
   byeLen:    equ $-bye               ; Length of 'Goodbye' string
   
section .text
   global _start

_start:
   mov eax,4            ; The system call for write (sys_write)
   mov ebx,1            ; File descriptor 1 - standard output
   
   mov ecx,hello        ; Move the string 'Hello' to ecx to be printed
   mov edx,0x5     ; Move the length of 'Hello' to edx to be printed
   
    int 80h              ; Display Hello
   
    mov eax,4            ; The system call for write (sys_write)
   mov ebx,1            ; File descriptor 1 - standard output
   
    mov ecx,bye          ; Move the string 'Goodbye' to ecx to be printed
    mov edx,byeLen       ; Move the length of goodbye to edx to be printed
   
    int 80h              ; Display Goodbye
   
   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


My latest program, working.

On a side note, this is the code I use to compile.

Code:
nasm -f elf64 -g -F stabs hello.asm
ld -o hello hello.o
./hello


I'm a normal human being, and I detect a question.
ephan wrote:
I got it, that's where it is different from Z80, but I can still specify which system call I want with register eax right?

Yes, you can. A good list of Linux system calls can be found here.
Thanks iSouvik, that link was very helpful.

My new question is quite complex:


Code:

section .data
    hello:     db 'Hello',10           ; 'Hello' plus a linefeed character
    helloLen:  equ $-hello             ; Length of the 'Hello' string
   
    theinput:  db ''
   
section .text
    global _start

_start:
    mov eax, 4            ; The system call for write (sys_write)
    mov ebx, 1            ; File descriptor 1 - standard output

    mov ecx, hello        ; Move the string 'Hello' to ecx to be printed
    mov edx, helloLen     ; Move the length of 'Hello' to edx to be printed

    int 80h               ; Display Hello
   
    mov eax, 3            ; The system call for read (sys_read)
   
    mov ecx, theinput     ; Variable where input is saved
    mov edx, 10           ; Length in bytes of the input
   
    int 80h               ; Get input
   
    mov eax,4             ; The system call for write (sys_write)
   
    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 can get the input and save it in the variable 'theinput'.

However, how would I display it after?


Code:

mov eax, 4                              ; For the system call write
mov ecx, theinput                    ;Save the variable to write in ecx
mov edx, -----------------


Instead of all the dashes I need the size of the variable "theinput", but I'm not quite sure of how to get it.

Thanks

EDIT

I tried this but no luck, any ideas?:


Code:
section .data
    hello:     db 'Hello',10           ; 'Hello' plus a linefeed character
    helloLen:  equ $-hello             ; Length of the 'Hello' string
   
    theinput:  db ''                   ; Declare string input
   
section .text
    global _start

_start:
    mov eax, 4            ; The system call for write (sys_write)
    mov ebx, 1            ; File descriptor 1 - standard output
    mov ecx, hello        ; Move the string 'Hello' to ecx to be printed
    mov edx, helloLen     ; Move the length of 'Hello' to edx to be printed
    int 80h               ; Display Hello
   
    mov eax, 3            ; The system call for read (sys_read)
    mov ecx, theinput     ; Variable where input is saved
    mov edx, 4            ; Length in bytes of the input
    int 80h
   
    mov eax,4             ; The system call for write (sys_write)
    mov eax, 4            ; For the system call write
    mov ecx, theinput     ; Save the variable to write in ecx
    mov edx, 4            ; Fixed input length
    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
[/b]
"db" would imply Data Byte. So, 1 is the length, I believe.

Edit: are you wanting to do this (in C)
Code:
main() {
  char theinput[200];
  char* hello = "Hello world";
  write(stdout, hello, strlen(hello));
  read(stdin, theinput, 200);
  write(stdout, theoutput, strlen(theinput));

  return 0;
}
Check here: http://www.int80h.org/strlen/
So I decided to use []'s to get the length of the string (first byte of the adress in memory of the string is the size):



Code:
section .data
    hello:     db 'Hello',10           ; 'Hello' plus a linefeed character
    helloLen:  equ $-hello             ; Length of the 'Hello' string
   
    theinput:  db ''                   ; Declare string input
   
section .text
    global _start

_start:
    mov eax, 4            ; The system call for write (sys_write)
    mov ebx, 1            ; File descriptor 1 - standard output
    mov ecx, hello        ; Move the string 'Hello' to ecx to be printed
    mov edx, helloLen     ; Move the length of 'Hello' to edx to be printed
    int 80h               ; Display Hello
   
    mov eax, 3            ; The system call for read (sys_read)
    mov ecx, theinput     ; Variable where input is saved
    mov edx, 4            ; Length in bytes of the input
    int 80h
   
    mov eax,4             ; The system call for write (sys_write)
    mov eax, 4            ; For the system call write
    mov ecx, theinput     ; Save the variable to write in ecx
    mov edx, [theinput]   ; Get input length
    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


When I inputted one, two or three character(s) I got:

Quote:
Hello
d
d

d�@D
�@D
�@D�@D�@D�@D�@D�@D�@D�@D�@D�@D�@D�@D�@D�@D�@dhello.asm.symtab.strtab.shstrtab.text.data.stab.stabstr�@�K!�`�'�-�
�688 pB�@�`��
�`��`#�@*��`6��`=�`hello.asmhellohelloLentheinput_start__bss_start_edata_end


But when I input 4 or more, the terminal closes immediately, no output.

Quote:
Whatever tutorial your were reading covered other system calls, I would think. Have you read that entire tutorial?


I don't know which tutorial you are talking about, but I found this book which seems good, but I haven't really gone deep with it.

Quote:
Edit: are you wanting to do this (in C)?

Code:

main() {
  char theinput[200];
  char* hello = "Hello world";
  write(stdout, hello, strlen(hello));
  read(stdin, theinput, 200);
  write(stdout, theoutput, strlen(theinput));

  return 0;
}


Yes, it's also called "cat program".
Because I have no experience in x86/64 asm, here is a strlen in z80:
Code:
;HL is the pointer to the string
;BC is the length
strlen:
  ld bc, 0
strlenloop:
  ld a,(hl)
  or a
  ret z
  inc bc
  inc hl
  jr strlenloop
Don't know if you can accurately translate that. Also, string sizes are stored nowhere in memory. That's why strings are null-terminated, because it is easier than storing the size in memory. Regarding the tutorial, I had just assumed that you were working off of one. Here is a better form of a cat program (in C), might help with concepts:
Code:
main() {
  char c;
  while((c = getc(stdin)) != '\0') {
    putc(c, stdout);
  }
}
Maybe you can translate that a little better than what you were trying to do. (Also, theinput in your program was of zero bytes, AFAICT. If anything, it was one byte).
ephan wrote:

When I inputted one, two or three character(s) I got:

Quote:
Hello
d
d

d�@D
�@D
�@D�@D�@D�@D�@D�@D�@D�@D�@D�@D�@D�@D�@D�@D�@dhello.asm.symtab.strtab.shstrtab.text.data.stab.stabstr�@�K!�`�'�-�
�688 pB�@�`��
�`��`#�@*��`6��`=�`hello.0x5


As Tanner observed, you're reserving one byte (at best (and referring to the NASM manual suggests you're getting one byte)) for the string buffer. A quick look at the NASM manual reveals you probably want to use resb and friends for such a thing (or take the C approach and allocate a buffer on the stack, which is best if you want to tear down the buffer upon return (usually do)).

You don't have enough buffer space, so just about anything could happen, hence it explodes. You got lucky that up to 4 bytes works, I think.


Code:
; Reserve 64 bytes in .data
sbuffer: resb 64

gets:
    mov eax, 3
    mov ebx, 1    ; stdin
    mov ecx, sbuffer
    mov edx, 63
    int 80h
    movb [sbuffer+63], 0
; do something with it...


The stack-allocation way (disclaimer: I didn't test this and it might be horribly wrong):

Code:

gets:
    push ebp
    mov ebp, esp
    sub esp, 64

    mov eax, 3
    mov ebx, 1
    mov ecx, esp
    mov edx, 63
    int 80h
    movb [esp+63], 0
; Do something with buffer at esp

; Tear down
    mov esp, ebp
    pop ebp
; Return or whatever

The second approach is a better way to do it most of the time, but at that point you're basically writing the same code a C compiler would generate anyway..
The usual cautions involving buffer overflows apply to both of these, but it would be easier to exploit the stack-based buffer. It's plausible that scribbling on the .data section could allow a denial-of-service attack though, so just always validate buffer sizes.

_player1537 wrote:

Code:
while ((c = getc(stdin)) != '\0')

That won't work as you expect. getc returns EOF on end-of-file (usually -1), not zero. 0 is perfectly legal on the input, hence the return type of getc is an int rather than unsigned char- it has to be able to represent a value outside the range of valid bytes to read from the file.
Also, Ithink when you input "d\n", you got what yougot because it was reading 100 bytes ahead (d's char code is 100).

Edit: Oops, thanks for the catch.
ephan wrote:
So I decided to use []'s to get the length of the string (first byte of the adress in memory of the string is the size):

I'm not sure where you learned that brackets would get the length of a string. They don't. Brackets around an address/symbol or a register dereferences the value stored at that address/register. It's basically like doing "ld a,(hl)" which loads the value that hl points to.

You can instead use the return value from the read system call. read returns how many bytes it read into your buffer (it's not a zero-terminated string) in the eax register. So before you start loading registers for the write syscall, add a "mov edx, eax" instruction.

Regarding the size your buffer (theinput), I believe you can use "ds 200" to reserve 200 bytes, instead of db, which only reserves 1 bytes for each item that is listed. ds also doesn't initialize the memory (or clears it to all zero bytes). All or most z80 assemblers support ds the same way.
_player1537 wrote:
Also, Ithink when you input "d\n", you got what yougot because it was reading 100 bytes ahead (d's char code is 100).

I was about to add something like that to my commentary. Smile

Assuming the first byte of the buffer is the size read immediately after calling read is entirely wrong. The manpage for read() says it returns the number of bytes read, so the following is more correct (but not complete.. fit it in as an exercise):

Code:

stringlength: resw 1
; blah blah blah
    int 80h
; ABI specifies return value in eax
    mov [stringlength], eax


You could also use the C library functions for printing strings (puts in this case would be useful) and use the length value read() gives you to plug a null terminator into the string before calling puts. Alternatively, iterate on eax, printing single characters.
Wait, so does variable "c" have to be an int, then? And then putc() would need me to cast "c" to a char? Also, on a semi-related note, does this return 255 or something else:
Code:
char test() {
  int a = -1;
  return (char)a;
}


Also, while I'm thinking about it, in x86 (and x64) ASM, how would you work with C's "int"s?
  
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 2 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