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 用のインクルードファイルを作成してシステムコールを利用しやす くする予定です.