백준 2557 Hello World 문제 풀이 (어셈블리)
백준 온라인 저지, 2557번: Hello World
도입
백준 온라인 저지에서는 어셈블리 언어 채점 환경을 NASM 32비트/64비트 구현체로 제공한다.
어셈블리 언어는 실행 환경에 따라 요구하는 코드 스펙이 조금씩 다르기 때문에, 채점 환경인 AWS EC2에 맞는 코드를 작성해야 한다.
구체적으로 NASM은 x86 아키텍처를 대상으로 하고, 백준 온라인 저지는 우분투 16.04 LTS를 사용하고 있다. (2023-02-15 기준; 2025-07-14 재확인됨.)
따라서 예를 들어, arm 아키텍처의 어셈블리 코드를 동작시킬 수 없고, 윈도우의 write 시스템 콜(NTWriteFile
)은 리눅스의 write
시스템 콜과 달라 백준 온라인 저지에서 채점할 수 없다.
가장 간단한 문제 중 하나인 2557번: Hello World 문제를 어셈블리 언어를 이용해 해결함으로써, 백준 채점 환경에서의 어셈블리 언어 사용법을 확인하고자 한다.
풀어보기
이 풀이에서는 .text
섹션과 .data
섹션을 사용한다. .text
섹션은 실행 가능한 코드가 위치하고, .data
섹션은 프로그램에서 사용하는 데이터를 저장한다.
section .text
global main
main:
main:
은 프로그램의 진입점이다. global
키워드로 컴파일러와 링커가 이 심볼에 접근할 수 있도록 한다.
이 어셈블리 코드는 리눅스 시스템에서 실행하는 것을 목표로 한다. 때문에 이와 같이 진입점을 선언하고 컴파일러와 링커가 이 심볼을 찾아 리눅스 시스템이 실행할 수 있도록 해야 한다.
시스템 콜
mov eax, 0x4
32비트 시스템에서 범용 레지스터는 eax
, ebx
, ecx
, edx
등으로 불린다. 이 레지스터에 시스템 콜 규칙에 따라 값을 작성하여 시스템 콜을 호출할 수 있다.
mov eax, 0x4
는 eax
레지스터에 4
를 저장한다. 0x4
는 리눅스에서의 write
시스템 콜 번호이다. write
시스템 콜은 특정한 데이터를 파일 디스크립터를 통해 파일에 작성한다.
1
ssize_t write(int fd, const void buf[.count], size_t count);
구체적인 write
시스템 콜 사용법은 write(2) - Linux manual page과 같다.
write
시스템 콜은 세 개의 인자를 더 받는다. 이어서 각각 ebx
, ecx
, edx
레지스터에 값을 작성하여 인자들을 전달한다.
mov ebx, 1
일반적으로 0
은 표준 입력, 1
은 표준 출력, 2
는 표준 에러를 나타낸다. 즉 mov ebx, 1
로 int fd
인자에 write
대상으로 표준 출력 파일 디스크립터를 지정한다.
이어서 코드가 사용할 데이터 값을 .data
섹션에 작성한다.
section .data:
msg: db "Hello World!", 0xa
msg_len: equ $-msg
msg
에 작성한 db "Hello World!", 0xa
는 문자열 “Hello World!”와 줄바꿈 문자를 바이트로 저장(db
는 define byte를 의미)한다. 0xa
는 줄바꿈 문자로, ASCII 코드에서 10이다.
msg_len
의 정의에서 equ
(Equate) 지시어는 상수를 정의하는데 사용된다. 구체적인 상수 값은 이어지는 코드에서 결정된다.
$
는 현재 위치를 나타내어서, $-msg
식으로 현재 위치로부터 msg
시작점까지의 거리를 계산한다. 다시 말해 msg_len
은 msg
문자열의 길이를 나타낸다.
mov ecx, msg
mov edx, msg_len
위 두 데이터 msg
, msg_len
은 write
시스템 콜에서 각각 const void buf[.count]
와 size_t count
인자에 투입된다.
인터럽트 발생
int 0x80
eax
, ebx
, ecx
, edx
레지스터에 값을 작성한 후에는 실제로 시스템 콜을 호출한다. 리눅스 시스템 콜은 0x80
인터럽트를 발생시켜 시스템 콜을 수행한다. 인터럽트 명령어는 int <인터럽트 번호>
이므로, 위와 같이 작성한다.
종료 상태 설정
0번 파일 디스크립터에 write
시스템 콜을 호출하였으므로, 문제가 요구하는 프로그램 동작은 완료되었다.
mov eax, 0x0
ret
리눅스 커널은 eax
레지스터에 작성된 값을 프로그램의 종료 상태로 사용한다. 따라서 eax
레지스터를 0으로 설정하지 않고 프로그램을 종료하면, 백준 채점 환경에서는 프로그램이 비정상적으로 종료되었다고 판단한다.
마무리
백준 온라인 저지에서 어셈블리 언어의 채점을 지원하여서, 어셈블리로 간단한 문제를 풀어보았다.
다만 백준 온라인 저지는 알고리즘 문제 풀이를 연습하기 위한 사이트이고, 알고리즘 연습에 어셈블리는 적절하지 않다.
그럼에도 어셈블리 코드를 채점할 수 있다는 사실은 백준 온라인 저지의 재밌는 점인 것 같다.