Hello World 에서 standard output 에 출력했다면
반대인 standard input 도 어렵지 않을 겁니다.
sys_read 의 시스템콜 id 는 0이고
sys_write 과 마찬가지로 3개의 인수(arguments)를
받습니다. rdi 파일 디스크립터, rsi 문자형 포인터(주소),
rdx는 바이트 사이즈입니다.
다른 디스트로는 모르겠는데 우분투
LTS 20.04의 경우 한글도 입력이 가능합니다.
리눅스의 내부처리 인코딩은 UTF-8 인 것으로
알고 있습니다. 어차피 syscall은 커널이
받아서 처리하는 거니까 콘솔 환경에서는
딱히 신경쓰지 않아도 됩니다.
그 다음에 section .bss 를 사용합니다.
.bss 는 (block starting symbol)의 약자로
아직 할당되지 않은 변수를 예약할 때
사용하는 영역입니다. bss section 이나
bss segment 라고도 합니다.
data segment 의 변수들은 초기화를
시켜줘야하는데 bss segment는 초기화 없이
사용가능합니다. 입력을 받기 위한 장소를
예약한다고 보면 됩니다.
아래의 코드에서 name resb 20은
name 이라는 심볼에 20바이트를 예약
(reserve byte) 하라는 뜻입니다.
section .data
text1: db "이름이 무엇입니까?",10, "-> "
text1_L: equ $-text1
text2 db "안녕하세요! "
text2_L: equ $-text2
section .bss
name resb 20
section .text
global _start
_start:
call _printText1
call _inputName
call _printText2
call _printName
call _exitProgram
_inputName:
mov rax, 0 ;syscall id sys_read
mov rdi, 0 ;file descriptor stdin
mov rsi, name ;reserved 20 bytes
mov rdx, 20 ;maximum bytes
syscall
ret
_exitProgram:
mov rax, 60
mov rdi, 0
syscall
_printText1:
mov rax, 1 ;syscall id 1 ->sys_write
mov rdi, 1 ;file descriptor stdout
mov rsi, text1 ;hello world text
mov rdx, text1_L ;byte length
syscall
ret ;return to where it called
_printText2:
mov rax, 1
mov rdi, 1
mov rsi, text2
mov rdx, text2_L
syscall
ret
_printName:
mov rax, 1
mov rdi, 1
mov rsi, name
mov rdx, 20
syscall
ret
출력하는 부분은 전의 포스팅에 상세히
설명했으므로 여기서는 input 에 대해서
알아보겠습니다.
일단 서브루틴으로 정리한 것은
어셈블리어다 보니까 코드가 지루해지니까
이름을 하나씩 붙였습니다. 뭔가 불필요하게
느껴지지만 이것들을 자동화하는 방법도
다 있습니다. 어셈블리어는 원초적인 레고블록
같은 거라서 얼마든지 원하는 알고리즘을
구현할 수가 있습니다. 그런 것들은 차츰
알아갈테니 지금은 sys_read 시스템콜에 집중합니다.
무엇인가 입력을 받을 메모리를 확보하는 것은
bss section 에서 20바이트를 해놓았습니다.
C언어로 치면 변수? 배열같은 것 입니다.
여기서는 byte 단위로 하니까 알아서 판단해야 합니다.
section .bss
name resb 20
그 다음에 입력받는 서브루틴입니다.
읽어보면 쉽게 이해할 수 있습니다.
mov rax,1
...
syscall
의 반대입니다. 출력의 반대개념으로
보면 키보드로 입력을 받아야 하고
(mov rdi, 0), 변수에 저장하고(name),
변수의 길이를 알아야 합니다.(20)
_inputName:
mov rax, 0 ;syscall id sys_read
mov rdi, 0 ;file descriptor stdin
mov rsi, name ;reserved 20 bytes
mov rdx, 20 ;maximum bytes
syscall
ret
출력하는 것은 변수인 name과
count 만 바꿔주면 됩니다.
_printName:
mov rax, 1
mov rdi, 1
mov rsi, name
mov rdx, 20
syscall
ret
*앞전 내용과 이어지니까 참고합니다.