Quantcast
Viewing all articles
Browse latest Browse all 5

Answer by Edward for Ubuntu 18.04.3 LTS get terminal columns and rows NASM

Here are some things that may help you improve your program

Use consistent formatting

The code as posted has irregular indentation, making it not so easy to read. Assembly language programs are typically very linear and neat. Also, I personally don't use tab characters in my code so that it looks the same everywhere (including printing), but that's a personal preference.

Provide the complete program

The program is missing the definition of sys_exit (which should have a value of 60). I'd suggest also telling reviewers how you've compiled and linked the program. Here's what I used:

nasm -o rowcol.o -f elf64 rowcol.asmld -o rowcol rowcol.o

Document register use

The comments in your program are generally quite good, but one thing lacking is documentation on how the registers are being used, which is one of the most important aspects to assembly language programming. The x86 architecture is unlike many others in that particular instructions require particular registers. For that reason, it's useful to identify when you'll need to use such instructions and base the register usage around that.

Avoid slow instructions

Although special-purpose instructions such as loop and repnz scasb seem appealing, they are, in fact, relatively slow. Instead, it's usually much faster (and not that many more code bytes) to do things with the more generic instructions.

Use address multipliers for efficiency

We can greatly simplify getting a pointer to the environment list into a register:

mov rbp, rsp            ; use rbp for stack pointermov rcx, [rbp + 0]      ; get argclea rbx, [rbp+8+8*rcx]  ; rbx now points to env

Understand environment variables

In Linux, there is a difference between shell variables and environment variables. Environment variables are what your program is searching, but the LINES and COLUMNS variables are shell variables that are set by the shell but typically not as environment variables. See this question for details.

Use an IOCTL

The reliable way to get the screen dimensions in Linux is to invoke the TIOCGWINSZioctl call. In C++ it would might look like this:

#include <sys/ioctl.h>#include <unistd.h>#include <iostream>int main () {    struct winsize w;    ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);    std::cout << "lines = "<< w.ws_row << "\ncolumns = "<< w.ws_col << '\n';}

So we just need to put that into assembly language. First, some constants:

sys_ioctl equ 0x10STDOUT_FILENO   equ 1TIOCGWINSZ equ 0x5413

Now the winsize structure:

struc winsize    .ws_row:     resw   1    .ws_col:     resw   1    .ws_xpixel:  resw   1    .ws_ypixel:  resw   1endstrucsection .bssw   resb winsize_size   ; allocate enough for the struc

Finally the call:

mov edx, wmov esi, TIOCGWINSZmov edi, STDOUT_FILENOmov eax, sys_ioctlsyscall; do stuff with window size...

If the call was successful (that is, if eax is 0) then the winsize structure is filled in with the current dimensions.


Viewing all articles
Browse latest Browse all 5

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>