Author Topic: beginner questions  (Read 96445 times)

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: beginner questions
« Reply #15 on: February 21, 2016, 06:29:50 PM »
1) Well you've got "glibc". It's just a C library - there are different versions. "libc6"(?) is another "important" one. Although this is alleged to be "standardized", if you haven't got the right version, it won't work. "gcc" stands for "Gnu Compiler Collection", but is the name of the C compiler. Although you don't "need" to use it, you may want to. Even if you don't have any C code to compile, gcc knows what to tell ld, and may be easier than composing the command line to ld yourself. Incidentally, "ld" (the linker) and "objdump" and some other things are part of the "binutils" package and are not part of "gcc" although they go together.

2) If you remember DOS, you probably loaded "ansi.sys" in "config.sys" (or possibly "autoexec.bat").  It gave us the interface where up-arrow recalled previous commands, and the "escape sequences". Printing a string to the screen with the "escape" character (27 or 0x1B) followed by '[' and some numbers and letters would clear the screen, or change colors, or "gotoxy"... and some other things I forget. The vt100 interface does the same for us. We really should consult the "termcap" file (/etc/termcap) to make sure it's supported, but it probably is, and would just print some garbage if it isn't.

3) You mention "gotoxy" being a macro, which it could be. That stuff from Jeff Duntemann had it just as a subroutine. He composes an "escape sequence" on the stack and calls "write", which in this case expects a zero-terminated string. You'd want to replace it with a 64-bit "write", but would use the same escape sequence (I think) - on a 64-bit stack, of course.
Code: [Select]
mov dl, [x_pos]
mov dh, [y_pos]
call gotoxy
The x- and y- in dx is copied from the bios interrupt - you could do it a different way...

4) "bash" is the  "bourne again shell" - the most common(?) of the shells Unix uses. It serves the same purpose as "command.com" or "cmd.exe". You've got it.

5) "xman" is just the graphical interface to the man pages. You almost certainly have it. On my machine, it's at "/usr/X11R6/bin/xman". You could find it with "locate xman" or "which xman". I mentioned that there's probably a way to do this through the cartoon interface but I didn't know it. Bryant told us the way - "xman".

6) The system call number goes in rax, first parameter in rdi, second in rsi, third in rdx (different parameters for something other than sys_write, of course), r8 after that, I think. After that I'd have to look 'em up. In 32-bit code, system calls with a lot of parameters sometimes put 'em in a structure with just one parameter (ebx) pointed to 'em, rather than  edi, esi, ebp. Dunno if 64-bit does that.

7) I think "video6" is a remnant of the bios interrupt, not yet converted to Linux. You probably don't have it and shouldn't need it.

8 ) "unistd.h" is the C header file with the system call numbers. To include it in a Nasm file, you'd have to convert it to Nasm syntax (Bryant showed us a one-line script to do that) and probably name it "unistd.inc". NASMX has both 32- and 64-bit versions "%if"ed  based on the output format so we get the right one. I mentioned that the man pages are in C format rather than asm format - such is life.

Best,
Frank


Offline jackjps

  • Jr. Member
  • *
  • Posts: 60
Re: beginner questions
« Reply #16 on: February 21, 2016, 09:53:12 PM »
;OBJ   : Display a character
;------------------------------------------------
;RDI   : Address of the character
;       > add64, reg64
;------------------------------------------------
;NOTE   : -
;RETN   : -
;------------------------------------------------
prtchar:   
   push rax
   push    rdi
   mov   al,byte[rdi]
   call   prtchr
   pop    rdi
   pop    rax
   ret

Where did they get "prtchr"? It's not in the man pages.
Same with a "Pause".  Where did they get "getch"?

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: beginner questions
« Reply #17 on: February 21, 2016, 10:52:55 PM »
Dunno that one. Who is "they"?

"pause" is an instruction (introduced with P4 I think). "getch" is C (or possibly in "curses"?).

Best,
Frank


Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: beginner questions
« Reply #18 on: February 21, 2016, 11:20:21 PM »
;OBJ   : Display a character
;------------------------------------------------
;RDI   : Address of the character
;       > add64, reg64
;------------------------------------------------
;NOTE   : -
;RETN   : -
;------------------------------------------------
prtchar:   
   push rax
   push    rdi
   mov   al,byte[rdi]
   call   prtchr
   pop    rdi
   pop    rax
   ret

Where did they get "prtchr"? It's not in the man pages.

It's defined within that file, it's just another procedure written by the author of that file. The man pages only document system calls and programs that are installed on the system. Using a text editor and searching for "prtchr:" takes me right to the following code:

Code: (nsm64.asm) [Select]
;--------------------------------
;#16 : prtchr(AL)
;OBJ : Display character in RAX
;--------------------------------
;ARG : The character in RAX(AL)
;--------------------------------
;NOTE : For internal use. Use prtchar
;RETN :
;--------------------------------
prtchr:
push rcx
push r11
push rdi
push rsi
push rdx
push rax
mov edx,1
mov rsi,rsp
mov edi,edx
mov eax,edx
syscall
pop rax
pop rdx
pop rsi
pop rdi
pop r11
pop rcx
ret

This is just a wrapper function that saves the registers and invokes the "write" system call (man 2 write). If you generate the file I mentioned earlier, you could look in there to see that SYS_write is defined as 1, in this example he puts 1 into EDX for the 'count' parameter to SYS_write and then reuses the value by copying it into EAX to specify the system call number to invoke with syscall instruction. Yeah, that's a lot to take in.. probably why it's listed as "For internal use".

Same with a "Pause".  Where did they get "getch"?

The getch procedure was defined on the line right after prtch:

Code: (nsm64.asm) [Select]
;------------------------------------------------
;#17 : getch(0)/AL
;OBJ : Get a character from keyboard
;------------------------------------------------
;ARG : -
;------------------------------------------------
;NOTE : Takes single character only
; : For internal use only. Use getchr.
;RETN : The key in AL
;------------------------------------------------
getch:
push rbp
mov rbp,rsp
sub rsp,16
push rdx
push rdi
push rsi
lea rsi,[rbp-2]
mov edx,1
xor edi,edi
xor eax,eax
syscall
xor eax,eax
mov al,byte[rbp-2]
pop rsi
pop rdi
pop rdx
mov rsp,rbp
pop rbp
ret

Once again, this is just a wrapper function that saves the registers and invokes the "read" system call (man 2 read). In this case, again referring to the unistd_64.inc file I told you to generate earlier, you can see that SYS_read is defined as 0. The author sets EAX to zero using the XOR instruction (because the exclusive OR of any value against itself is zero). This is a trick I'm guilty of using often myself, but makes the code less readable (which is why this code is also marked as "For internal use only.").

As Frank pointed out, the "they" here in your post wasn't exactly obvious. Took me a bit of searching to realize you were making a reference to an earlier post you had made on a different thread. Probably would have gotten an answer sooner if you had pointed out where you got the code you were using, that helps us help you.  ;D

Regards,
Bryant Keller

About Bryant Keller
bkeller@about.me

Offline jackjps

  • Jr. Member
  • *
  • Posts: 60
Re: beginner questions
« Reply #19 on: February 22, 2016, 12:57:30 AM »
I did get unistd_64.inc installed.
I see that I am going to have to watch what's in the rdx and
rdi registers. Yes, I didn't connect the 1st sample code to the 2nd
one. Didn't know that I had to do that. What does mov rsi,rsp do?

Seems this code is to ambiguous. I would think it could be written
in a straight forward manner. This kind of code is hard to decipher
6 months down the road. But what do I know.
Thank you for your response.

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: beginner questions
« Reply #20 on: February 22, 2016, 02:37:31 AM »
Thanks, Bryant! I didn't recognize that.
Quote
What does mov rsi,rsp do?
Since we're calling sys_write, rsi is the parameter that gives the address of the buffer that we're going to print. Since we pushed rax, and al holds the character we want to print, it tells sys_write that the character's on the stack. Since we started out with rdi pointed to the character,
Code: [Select]
mov rsi, rdi
might have been more straightforward, but might not have preserved all the registers we want to preserve. Or maybe it just seemed like a good idea at the time.

Quote
But what do I know.
Sounds like you know:
Quote
This kind of code is hard to decipher
6 months down the road.
On that, I think we are all agreed!

Best,
Frank


Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: beginner questions
« Reply #21 on: February 22, 2016, 04:24:09 AM »
Thanks, Bryant! I didn't recognize that.

No problem.

Quote
This kind of code is hard to decipher
6 months down the road.
On that, I think we are all agreed!

Absolutely. I wouldn't suggest you try and learn from code like that. The code looks more like a wrapper to abstract the learner from the system, but what your wanting is to learn to code on a specific system. You need less abstractions, not more. :)

That said, I suggest you check out this awesome 64-bit NASM tutorial. I find myself recommending it a lot lately (and it's still not 100% complete). The coding style is clean, easy to read, and even the web page is quite well put together. What's more, he covers everything you've been trying to learn, check it out.

NASM Tutorial by Ray Toal

About Bryant Keller
bkeller@about.me

Offline jackjps

  • Jr. Member
  • *
  • Posts: 60
Re: beginner questions
« Reply #22 on: February 22, 2016, 11:43:59 AM »
Thanks guys for putting up with me.
To Bryant,
I downloaded the NASM Tutorial by Ray Toal.
Lot in it . Will take me ages to absorb it.

In converting my 1st windows program these are some
of the things I need to do in NASM:
  create a full screen of a light blue color.
  put a small rectangle on the screen in yellow.
  let the user enter 4 digits in black in that rectangle.
  read the 4 digits from the rectangle.
Right now I can't get past the 1st item.

 



Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: beginner questions
« Reply #23 on: February 22, 2016, 07:53:56 PM »
To Bryant,
I downloaded the NASM Tutorial by Ray Toal.
Lot in it . Will take me ages to absorb it.

Before you start any major projects on Linux, I would suggest reading that tutorial up to, and including, the section entitled "Understanding Calling Conventions". Once you understand how to interface with the system and make calls to the standard C library, you can then move forward to developing other stuff.

In converting my 1st windows program these are some
of the things I need to do in NASM:
  create a full screen of a light blue color.
  put a small rectangle on the screen in yellow.
  let the user enter 4 digits in black in that rectangle.
  read the 4 digits from the rectangle.
Right now I can't get past the 1st item.

I'll assume you want to do this in text mode, and that itself presents a few problems.

1st problem is that not all Linux systems are the same. What I mean by this is, Linux runs on a lot of different hardware and there are many different configurations and software options that the distribution mostly gets to customize themselves. The reason why this is a problem is because each terminal acts differently. Unlike DOS applications, when you open a console, you're actually connected through a Virtual Terminal (VT) to the system. These VTs emulate one of the popular terminals from the olden days of DEC's and HK's.. however, each of those terminals were built by different vendors and had different escape sequences for doing things beyond just text (like clearing the screen and changing text attributes). When people started building VTs for Linux, they did so around supporting the real terminals they liked and this has lead to a lot of options. Fortunately, however, this is mostly just an issue with history because almost every system I've ever used makes use of some form of DEC based VT (VT100, VT220, etc) but even those DEC ones (same vendor) aren't 100% the same. In fact, some don't even support color.

So how do we solve this problem? Well.. the same way you solve most problems with system dependency, through abstraction. If you put a portability layer between you and those terminals, you can develop code that should (in most cases) work on all those VTs. Luckily, you're not the first person to want this kind of abstraction. There is a C library called ncurses which provides a portable method of doing terminal graphics.

About Bryant Keller
bkeller@about.me

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: beginner questions
« Reply #24 on: February 22, 2016, 08:00:36 PM »
To demonstrate the use of ncurses, I took your program example and turned it into a basic use case then developed a demo app. Here's the source. Unfortunately, I run a 32-bit system so if you want to make this into a 64-bit demo.asm, you'll need to visit that tutorial and work your way through and convert this source. I stuck to libraries written in C so that you don't have to worry about calling conventions changing on you, both libc and libncurses are written in C.

Code: (demo.asm) [Select]
; Use Case:
;  - create a full screen of a light blue color.
;  - put a small rectangle on the screen in yellow.
;  - let the user enter 4 digits in black in that rectangle.
;  - read the 4 digits from the rectangle.

; Dependencies:
;  libc-dev          - GNU C library.
;  libncurses-dev    - Developer's libraries for ncurses.

; Build Process:
;  nasm -f elf demo.asm -o demo.o
;  gcc -o demo demo.o -lcurses


   bits 32
   cpu 586

   global main

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions from the Standard C Library
   extern signal
   extern atoi
   extern exit

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions from the NCurses Library
   extern initscr
   extern keypad
   extern nonl
   extern cbreak
   extern echo
   extern has_colors
   extern start_color
   extern init_pair
   extern newwin
   extern endwin
   extern refresh
   extern wrefresh
   extern wgetnstr
   extern wbkgd

   extern LINES
   extern COLS

   %define SIGINT 2  ; defined in signal.h
   %define TRUE   1  ; defined in curses.h
   %define FALSE  0  ; defined in curses.h

   %define COLOR_BLACK     0
   %define COLOR_RED       1
   %define COLOR_GREEN     2
   %define COLOR_YELLOW    3
   %define COLOR_BLUE      4
   %define COLOR_MAGENTA   5
   %define COLOR_CYAN      6
   %define COLOR_WHITE     7
   %define COLOR_PAIR(n) ((n) << (8))

   %define BLACK_ON_BLUE   1
   %define BLACK_ON_YELLOW 2

section .data

hWindow:       dd 0
hChildWindow:  dd 0
szUserInput:   db 0, 0, 0, 0, 0

section .text

;; do_init : nothing -> boolean .
;; preform all of the applications initialization.
;; when initialization was successful, hWindow will
;; contain the curses screen handle and the return
;; value will be TRUE. otherwise, it returns FALSE.
do_init:

   ;; setup an interrupt to terminate
   push dword do_exit
   push dword SIGINT
   call signal
   add esp, (2 * 4)

   ;; initialize the curses library
   call initscr

   ;; was curses initialization successful?
   cmp eax, 0
   jne .CursesInitSuccessful

   ;; initialization failed, return FALSE
   mov eax, FALSE
   ret

.CursesInitSuccessful:
   ;; save a copy of curses root window
   mov dword [hWindow], eax

   ;; enable keyboard mapping
   push dword TRUE
   push dword [hWindow]
   call keypad
   add esp, (2 * 4)

   ;; tell curses not to translate LF into CRLF on output
   call nonl

   ;; take input chars one at a time, no waiting for newline
   call cbreak

   ;; enable echoing of input
   call echo

   ;; does this system support color terminals?
   call has_colors
   cmp eax, 0
   jne .HasColorSupport

   ;; No color support, return FALSE
   mov eax, FALSE
   ret

.HasColorSupport:
   call start_color

   ;; create our color pairs

   ;; black foreground, blue background
   push dword COLOR_BLUE
   push dword COLOR_BLACK
   push dword BLACK_ON_BLUE
   call init_pair
   add esp, (3 * 4)

   ;; black foreground, yellow background
   push dword COLOR_YELLOW
   push dword COLOR_BLACK
   push dword BLACK_ON_YELLOW
   call init_pair
   add esp, (3 * 4)

   ;; lets create a child window

   push dword 50  ; x value
   push dword 10  ; y value
   push dword 5   ; 5 columns for 4 digits.
   push dword 1   ; 1 line for 1 row of digits.
   call newwin
   add esp, (4 * 4)
   mov [hChildWindow], eax

   ;; if we reach this point, we have initialized successfully.
   mov eax, TRUE
   ret

;; do_exit : integer -> nothing .
;; exit to the operating system.
do_exit:
   enter 0, 0

   ;; refresh our screen
   call refresh

   ;; shut down curses
   call endwin

   ;; return to operating system
   push dword 0
   call exit
   add esp, 4

   ;; we should never reach this point
   leave
   ret

;; clear_blue : nothing -> nothing .
;; create a full screen of a light blue color.
clear_blue:

   ;; make our background blue
   push dword COLOR_PAIR(BLACK_ON_BLUE)
   push dword [hWindow]
   call wbkgd
   add esp, (2 * 4)

   ;; refresh our screen
   push dword [hWindow]
   call wrefresh
   add esp, 4

   ret

;; draw_child_window : nothing -> nothing .
;; put a small rectangle on the screen in yellow.
draw_child_window:

   ;; make our background yellow
   push dword COLOR_PAIR(BLACK_ON_YELLOW)
   push dword [hChildWindow]
   call wbkgd
   add esp, (2 * 4)

   ;; refresh our child window
   push dword [hChildWindow]
   call wrefresh
   add esp, 4

   ret

;; get_user_input : nothing -> integer .
;; let the user enter 4 digits in black in that rectangle.
get_user_input:

   ;; get user input
   push dword 4 ; 4 characters
   push dword szUserInput
   push dword [hChildWindow]
   call wgetnstr
   add esp, (3 * 4)

   ;; convert string to integer
   push dword szUserInput
   call atoi
   add esp, 4
   ret

;; main : integer (string . string) -> integer .
;; our program starts here.
main:
   enter 0, 0

   call do_init
   cmp eax, TRUE
   jne .done

   ;; clear the screen to blue
   call clear_blue

   ;; draw yellow window
   call draw_child_window

   ;; get user input
   call get_user_input





   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ;; At this point in our code, the number we ;;
   ;; entered into our child window is in the  ;;
   ;; EAX register. We can now use it for any- ;;
   ;; thing we want.                           ;;
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;




.done:
   push dword 0
   call do_exit
   leave
   ret

About Bryant Keller
bkeller@about.me

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: beginner questions
« Reply #25 on: February 22, 2016, 08:04:02 PM »
One of many...

http://www.termsys.demon.co.uk/vtansi.htm

Code: [Select]
global _start
; nasm -f elf32 bluescreen.asm
; ld -o bluescreen bluescreen.o -m elf_i386

section .data
bluescreen db 27, '[30;44m'
bluescreen_len equ $ - bluescreen

yellow db 27, '[30;43m'
yellow_len equ $ - yellow

cls db 27, '[2J'
cls_len equ $ - cls

msg db "hello vt100"
msg_len equ $ - msg


section .text
_start:
    mov eax, 4 ; sys_write
    mov ebx, 1 ; STDOUT
    mov ecx, bluescreen
    mov edx, bluescreen_len
    int 80h

    mov eax, 4 ; sys_write
    mov ebx, 1 ; STDOUT
    mov ecx, cls
    mov edx, cls_len
    int 80h

    mov eax, 4 ; sys_write
    mov ebx, 1 ; STDOUT
    mov ecx, yellow
    mov edx, yellow_len
    int 80h

    mov eax, 4 ; sys_write
    mov ebx, 1 ; STDOUT
    mov ecx, msg
    mov edx, msg_len
    int 80h


exit:
    mov ebx, 0
    mov eax, 1
    int 80h

This is extremely naive. It doesn't do exactly what you want, but may get you started. You will want to convert it to 64-bit, no doubt.

Best,
Frank


Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: beginner questions
« Reply #26 on: February 22, 2016, 08:40:24 PM »
I forgot to mention one more Linux command: "reset". Learn to type it without seeing the letters and it may save your sanity if you're going to mess with the screen. :)

Bryant is right, of course. He's showing you how you "should" do it, I'm showing you how you "can" do it. If you're going to call C libraries, what's the assembly language for? Shouldn't you be programming in C? Assembly language is obsolete, isn't it? Just Joking!

(but seriously, they completely effed up the calling conventions in 64-bit - they are NOT the same!)

Best,
Frank


Offline jackjps

  • Jr. Member
  • *
  • Posts: 60
Re: beginner questions
« Reply #27 on: February 22, 2016, 08:52:58 PM »
Thanks again guys,
Oh my, I'm a glutton for punishment.
I think I have the glibc library. Not sure if I have the
ncurses library. I guess I have to look at the glibc
library through man. When I do man and an item
from the ncurses library nothing happens.
Will do my reading and conversion of Bryants program
until I heard about the ncurses library. Didn't think
I would have to get so involved with "C". But whatever
I have to do..... Windows 10 is an advertising mill by
a software company that has left the programming field! 

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: beginner questions
« Reply #28 on: February 22, 2016, 09:19:05 PM »
Bryant is right, of course. He's showing you how you "should" do it, I'm showing you how you "can" do it.

Well, I'm showing the way you can do it to get the most portability between terminals.. As for how you "should" do it... we'll, I can't exactly agree, I probably should have done better at documenting, it definitely needs refactoring  (though I was going for almost 1-1 translation to his use case), and I should probably check to make sure the string taken from my child window is actually a numeric value... but as far as a demo, it's fine. :P

If you're going to call C libraries, what's the assembly language for? Shouldn't you be programming in C? Assembly language is obsolete, isn't it? Just Joking!

I'm one of those weird people who actually find it easier to code in assembly than I do in high level languages. When I program in C I always feel like I'm fighting with the language to explain some concept that really shouldn't be so complicated. Assembler just gets out of my way and allows me to be productive.

To be honest, the languages I've always been most productive in have been Assembly, Scheme, and Forth.. though most work I've had to do professionally has been in C/C++, Fortran95, or Perl.

(but seriously, they completely effed up the calling conventions in 64-bit - they are NOT the same!)

Yeah, I still don't own a 64-bit machine, probably won't until Linux drops support for IA32...  :-[

Thanks again guys,
Oh my, I'm a glutton for punishment.
I think I have the glibc library. Not sure if I have the
ncurses library. I guess I have to look at the glibc
library through man. When I do man and an item
from the ncurses library nothing happens.

Check your distribution for ncurses-doc. that's the manual pages. For Debian, I installed ncurses using:

Code: (bash) [Select]
$ sudo apt-get install libncurses5-dev ncurses-doc
Will do my reading and conversion of Bryants program
until I heard about the ncurses library. Didn't think
I would have to get so involved with "C". But whatever
I have to do.....

You build code on top of other libraries all the time. Even the WinAPI was just an abstraction on top of the kernel mode API which is a library built on top of the BIOS which can be thought of as just yet another library. Since Linux is built on C and most of your applications are already running on top of the standard C library, there is very little reason not to use it.. It's there anyway. :P

Windows 10 is an advertising mill by
a software company that has left the programming field!

I've not used Windows since Win2k Professional...  ;D

About Bryant Keller
bkeller@about.me

Offline jackjps

  • Jr. Member
  • *
  • Posts: 60
Re: beginner questions
« Reply #29 on: February 22, 2016, 09:36:22 PM »
Thanks again Guys,
Got ncurses installed.
Changed the Demo  to 64 bit.
When I 1st ran the program it gave this error message:
no instruction for this cpulevel. Changed it to 686 and
got the same message.