[Assembly Language] 시스템콜 에러처리

Joey Hong·2020년 12월 23일
0

Assembly Language

목록 보기
2/2

error 처리

🎯 외부 함수 __error를 사용해서 errno의 값을 세팅해줄 것

  • Your code must set the variable errno properly.
  • For that, you are allowed to call the extern ___error.

errno란?

🎯 error number의 줄임말로, 가장 최근 에러의 번호를 담는 integer 타입 변수다

  • 프로그램이 시작하면 errno는 0으로 초기화된다

    • 일부 함수들은 에러가 감지됐는지 확인하기 위해 작업 전에 errno를 미리 0으로 설정해둔다고 한다
  • 에러가 생기면 시스템 콜 함수는 NULL이나 -1 등을 반환한다.

  • 에러 타입을 파악하기 위해 외부변수 errno에러 번호가 담긴다

  • 매뉴얼 페이지에서 에러 번호에 따른 에러 타입을 명시하고 있다

man errno

When a system call detects an error, it returns an integer value indicating failure (usually -1) and sets the variable errno accordingly. <This allows interpretation of the failure on receiving a -1 and to take action accordingly.> Successful calls never set errno; once set, it remains until another error occurs.

...

0 Error 0. Not used.
1 EPERM Operation not permitted. An attempt was made to perform an operation limited to processes with appropriate privileges or to the owner of a file or other resources.

2 ENOENT No such file or directory. A component of a specified pathname did not exist, or the pathname was an empty string.

...


___error() 함수란?

🎯 errno의 주소를 리턴하는 함수

  • ___error() 함수는 외부함수다 (extern)
  • ___error() 함수는 에러번호를 담은 errno의 주소를 리턴한다
    • ___error()의 리턴값 타입은 int*
# /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/include/sys/errno.h

extern int * __error(void);
#define errno (*__error())

error_stackoverflow


___error()가 필요한 경우

🎯 errno에 에러번호를 세팅하려면 errno의 주소가 필요하다 (___error의 리턴값)

  • FreeBSD에서는 시스템콜이 errno를 세팅하는 대신 errno를 바로 리턴하고 carry flag를 1로 바꿔준다고 한다

    • FreeBSD는 정통 유닉스 운영체제며 Mac OS X의 일부가 FreeBSD를 바탕으로 개발되었다고 한다

    • 때문에 Mac OS X 를 사용하는 컴퓨터에서는 시스템 콜 에러시 직접 시스템 콜의 리턴값을 -1로 세팅하고 변수 errno에 에러넘버를 세팅해주어야한다

      wiki FreeBSD

  • write나 read 함수 매뉴얼의 리턴값 설명을 보면 -1을 리턴하고 errno라는 변수를 세팅하라고 되어있다

    • 따라서 write나 read 함수에서 ___error()를 호출하면 된다

      man 2 write
      man 2 read

      Otherwise, a -1 is returned and the global variable errno is set to indicate the error.

42libasm error handling


___error() 함수 사용법

🥊 에러가 발생하면 -1을 리턴하고 ___error를 사용해서 errno의 값을 세팅

  • write 함수에서 에러가 발생하면 carry flag 가 1로 바뀌고 rax에 에러 넘버가 저장된다
  • carry flag가 1이 되면 set_error 함수로 jump 한다
  • rax는 사용할 것이기때문에 rcx에 에러 넘버를 백업해둔다
    • rdi, rsi, rdx는 write 함수에서 사용되므로 추가 저장소는 rcx 등의 다른 레지스터를 사용한다
  • 외부함수인 ___error를 호출하면 rax의 에러 넘버를 보고 해당 errno의 주소를 리턴해준다
    • 여기서 errno는 외부변수
  • errno의 주소에 에러 넘버(rcx에 담긴넘버)를 넣어주어 errno를 세팅해준다
  • 마지막으로 rax에 -1을 담아 리턴해준다
;_ft_write.s
section	.text
global _ft_write			    ; fd = rdi, buf = rsi, bytes count = rdx
extern ___error

_ft_write:	mov         rax, 0x2000004
            	syscall
            	jc          set_error        ; if error, carry flag = 1, rax = error number
            	ret
set_error:
            	mov         rcx, rax         ; save error number to rcx
            	call        ___error         ; returns errno's address: rax = errno address
            	mov         [rax], rcx       ; save error number to errno address value
            															 ; errno = error number, rax -> errno
            	mov         rax, -1	     ; return value rax = -1
            	ret

42libasm error handling

profile
개발기록

0개의 댓글