3. 少し実用的なプログラム -- ウィンドウサイズの取得 --

少しだけ実用的なプログラムを作成してみます.

Linux のコンソールは 80文字25行 が普通ですが,例えば フレームバッファ を有効にしている場合や,Windows マシンから telnet 経由でログインしたり, X で xterm, kterm, rxvt, eterm から利用している場合は 80文字25行 以外の ウィンドウサイズが可能となります.

現在のウィンドウサイズを知りたいと思ったことはありませんか? 私は思いました. で, 以下のプログラムです.

ioctl システムコール,カーネルヘッダで宣言されている構造体の利用など 「hello, world」の次の例としては難解ですが,NASM の使用例です. おいおい解説していきます.

  ;---------------------------------------------------------------------
  ;   Display current window size
  ;   2000/01/16 Jun Mizutani
  ;     nasm -f elf ws.asm
  ;     ld -s -o ws ws.o
  ;     ndisasm -b 32 ws
  ;   usage : ws
  ;---------------------------------------------------------------------

  section .bss

  struc winsize
          .ws_row     resw 1
          .ws_col     resw 1
          .ws_xpixel  resw 1
          .ws_ypixel  resw 1
  endstruc

  wsize istruc winsize
          .ws_row     resw 1
          .ws_col     resw 1
          .ws_xpixel  resw 1
          .ws_ypixel  resw 1
        iend

  section .text
  global _start

  %assign TIOCGWINSZ      0x5413

  ;------------------------------------
  ; start here
  ;------------------------------------
  _start:
                 mov    eax, 54         ; sys_ioctl
                 mov    ebx, 0          ; to stdout
                 mov    ecx, TIOCGWINSZ ; get wondow size
                 mov    edx, wsize
                 int    0x80            ; call kernel
                 xor    eax, eax
                 mov    ax, [edx + winsize.ws_col]
                 call   PRINT_LEFT
                 mov    eax, "x"
                 call   OUTCHAR
                 xor    eax, eax
                 mov    ax, [edx + winsize.ws_row]
                 call   PRINT_LEFT
                 call   CRLF
                 mov    eax, 1          ; sys_call 1 : exit
                 mov    ebx, 0          ; exit with code 0
                 int    0x80
                 hlt

  ;------------------------------------
  ; Output Number to stdout
  ; eax : number
  ;------------------------------------
  PRINT_LEFT:
                 pusha
                 test   eax, eax
                 jns    .PL0
                 neg    eax            ; negative number
                 push   eax
                 mov    al, '-'
                 call   OUTCHAR
                 pop    eax
     .PL0
                 mov    ecx, 8
                 mov    edi, 10
                 mov    esi, 0
                 mov    ebx, 100000000
     .PL1:
                 call   PLSUB
                 xchg   eax, ebx       ;  : save eax
                 xor    edx, edx       ; ebx = ebx / 10
                 div    edi            ;  :
                 xchg   eax, ebx       ;  : restore eax
                 loop   .PL1

                 add    al, '0'
                 call   OUTCHAR
                 popa
                 ret

     ;--------------------------------
     ; Print Largest 1 digit
     ;--------------------------------
     PLSUB:
                 xor    edx, edx       ; edx = 0
                 div    ebx            ; eax = edx:eax / ebx
                 push   edx            ; modulo
                 test   eax, eax
                 jz     .PS1           ; if eax = 0 then just return.
                 add    al, '0'
                 call   OUTCHAR        ; print 1 digit
                 inc    esi            ;
                 jmp    short  .PS2
     .PS1:
                 test   esi, esi       ; suppress leading 0
                 jz     .PS2
                 mov    al, '0'
                 call   OUTCHAR
     .PS2:
                 pop    eax            ; modulo
                 ret

  CRLF:
                 mov    al, 0AH
  OUTCHAR:
                 pusha
                 push   eax            ; work buffer on stack
                 mov    eax, 4         ; sys_write
                 mov    ebx, 1         ; to stdout
                 mov    edx, 1         ; 1 char
                 mov    ecx, esp
                 int    0x80
                 pop    eax
                 popa
                 ret

NASMのマクロ機能を多用するとCPUの命令(オペコード)がわかりにくくなるため, マクロはあえて使用していません.

システムコール番号を直接指定していますが,あとの例ではカーネルのヘッダ から NASM 用のインクルードファイルを作成してシステムコールを利用しやす くする予定です.