수행할 case N를 입력하고 각각이 case에서는 입력한 문자열의 각 문자들을 입력한 정수만큼 반복하여 출력시켜주면 됩니다
어셈블리로 삼중으로 반복문을 사용해보니까 코드를 헷갈리는 경우가 있었는데 주석의 중요성을 다시금 느끼는 것 같습니다
global main
extern scanf
extern printf
section .text
main:
push rbp
mov rbp, rsp
sub rsp, 0x30
xor rax, rax
mov [rbp-0x8], rax ; N
mov [rbp-0x10], rax ; input
mov [rbp-0x18], rax ; for i
mov [rbp-0x20], rax
mov rdi, input_N
lea rsi, [rbp-0x8]
call scanf ; intput N
loop:
mov rax, [rbp-0x8]
test rax, rax
je _exit
mov rdi, input
lea rsi, [rbp-0x10]
lea rdx, [array]
call scanf ; input
xor rax, rax
mov [rbp-0x20], rax
jmp loop_index
inc_index: ; inc index [array + index]
inc qword[rbp-0x20]
loop_index:
xor rax, rax
mov rcx, [rbp-0x20]
mov al, byte[array + rcx]
cmp rax, 0x0 ; check if its 0x00
je next_loop
xor rax, rax
mov [rbp-0x18], rax
loop_print:
mov rax, [rbp-0x10]
mov rcx, [rbp-0x18]
cmp rax, rcx
je inc_index
xor rax, rax
mov rcx, [rbp-0x20]
mov al, [array + rcx]
mov rdi, output
mov rsi, rax
call printf
inc qword[rbp-0x18]
jmp loop_print
next_loop:
dec qword[rbp-0x8]
mov rdi, output
mov rsi, 0xa
call printf
jmp loop
_exit:
xor rax, rax
leave
ret
section .data
array: TIMES 21 db 00
input_N: db "%d",00
input: db "%d %s",00
output: db "%c",00
주요 코드를 하나하나 보기 전에 다시금 리뷰해보면 case를 입력 후 반복할 정수와 문자열을 case만큼 반복하는 반복문이 하나 등장합니다
그리고 배열을 한 바이트씩 증가시키면서 각 바이트가 00 즉 문자열의 끝이 되기 전까지 각 문자를 정수만큼 반복해주는 과정을 이중 반복문으로 작성하였습니다 문자를 출력해주는 코드를 함수로 따로 뺐으면 가독성이 더욱 좋을 법도 한데
main:
push rbp
mov rbp, rsp
sub rsp, 0x30
xor rax, rax
mov [rbp-0x8], rax ; N
mov [rbp-0x10], rax ; input
mov [rbp-0x18], rax ; for i
mov [rbp-0x20], rax
mov rdi, input_N
lea rsi, [rbp-0x8]
call scanf ; intput N
main함수에서 가장 먼저 [rbp-0x8]에 case N을 scanf함수로 입력을 받습니다
loop:
mov rax, [rbp-0x8]
test rax, rax
je _exit
mov rdi, input
lea rsi, [rbp-0x10]
lea rdx, [array]
call scanf ; input
xor rax, rax
mov [rbp-0x20], rax
jmp loop_index
case N을 입력받은 뒤에 loop가 되는데 test instruction을 통해 [rbp-0x8]이 0이 될 때까지 [rbp-0x10]에 반복할 정수를 입력하고 array에 문자열을 입력하여 줍니다 [rbp-0x8]은 test를 즉 0일 때 main함수를 종료시키는 _exit으로 점프하기 때문에 하위 코드에서 dec qword[rbp-0x8]을 통해 [rbp-0x8]을 1씩 감소시키면서 loop가 진행됩니다
inc_index: ; inc index [array + index]
inc qword[rbp-0x20]
loop_index:
xor rax, rax
mov rcx, [rbp-0x20]
mov al, byte[array + rcx]
cmp rax, 0x0 ; check if its 0x00
je next_loop
xor rax, rax
mov [rbp-0x18], rax
loop_print:
mov rax, [rbp-0x10]
mov rcx, [rbp-0x18]
cmp rax, rcx
je inc_index
xor rax, rax
mov rcx, [rbp-0x20]
mov al, [array + rcx]
mov rdi, output
mov rsi, rax
call printf
inc qword[rbp-0x18]
jmp loop_print
next_loop:
dec qword[rbp-0x8]
mov rdi, output
mov rsi, 0xa
call printf
jmp loop
이전 코드 마지막에 jmp loop_index라는 instruction이 있었습니다 이는 초기에 inc_index의 코드를 수행하지 않기 위함인데요 [rbp-0x20]은 array의 index를 증가시키기 위해 사용되기 때문에 초기에는 [array + 0]을 검사해주기 위해 있고 다음 loop부터는 [rbp-0x20]을 1씩 증가함으로써 다음 index를 출력해주기 위해 inc_index를 점프하도록 하고 다음 루프부터는 실행시키도록 하였습니다
그래서 loop_index를 보면 문자열의 끝(0)인지를 확인하고 그렇다면 nex_loop로 점프하여 [rbp-0x8]을 1 감소시키고 printf를 통해 줄바꿈을 수행한 뒤 다음 정수와 문자열을 입력받기 위해 loop로 jmp 하게 됩니다
만약 문자열 index의 끝이 아니라면 loop_printf로 가게되는데
loop_print에서는 실직적으로 정수만큼 해당 문자열의 문자를 출력해줍니다 그리고 정수만큼 출력이 되었다면 그때 inc_index로 점프하여 index를 1 증가시키고 1 증가시킨 문자열의 문자를 다시 정수만큼 출력시키도록 하였습니다
***꽤나 코드를 복잡하게 짠 것 같아서 다시 복기하면서도 복잡한 거 같다 싶었는데... 조금 더 가독성 있게 코드를 짜는 방법도 꾸준히 생각해봐야 할 것 같습니다
'자료구조, 알고리즘 > x64 assembly' 카테고리의 다른 글
쌩 어셈블리로 두수 더하기 (0) | 2021.12.28 |
---|---|
백준 1157 단어 공부 (0) | 2021.11.11 |
백준 25577번 숫자의 개수 (0) | 2021.10.31 |
백준 2741 N 찍기 (0) | 2021.10.30 |