어셈블리어로 별 피라미드 만들기
nano pyramid.s 로 파일을 만들어주자
section .data
STAR db '*'
EMPTY db 0x0a
section .text
global _start
_start:
mov rax, 1
mov rdi, 1
mov rdx, 1
mov r10, 0
mov r9, [rsp +16]
cmp r9, 0
je _done
mov cl, [r9]
movzx r9, cl
sub r9, 0x30
mov r8, r9
xor r9, r9
call _syscall
STAR 라는 변수를 만들어주고 *이라는 포인터값이 들어가게 만들어주고
EMPTY 라는 변수는 0x0a를 넣어주는데 아스키코드에선 줄바꿈을 의미
_start라는 하나의 함수 정의하고
mov rax, 1 은 write라는 시스템 콜 설정
mov rdi, 1 기본 출력 모드
mov rdx, 1 출력 길이 설정
mov r10, 0 은 인덱스
mov r9, [rsp + 16] r9는 현재 입력된 문자열을 찾음 매개변수가 rsp 아래에 위치 즉 프로그램을 실행하여 입력하는 값이 rsp+16 안에 담김
cmp r9, 0 은 입력이 없는 경우
je_done 프로그램 종료
mov cl, [r9] 는 한 바이트만 cl에 저장(1~9층 사이로 할 것이기 때문)
movzx r9, cl 문자 형태의 cl을 r9에 저장
sub r9, 0x30 r9에 0x30을 빼주기 이렇게 해줌으로써 r9도 인덱스가 됨
RSP위치에서 16을 더해준게 입력한 매개변수가 담겨있는 메모리 주소를 가리키는 값
16진수로 30은 문자 '0'임
7을 넣는다면 16진수로 37 즉 30을 빼줌으로써 실질적인 숫자가 됨
r8에 r9를 넣어주고 xor r9, r9 를 해줘서 r9를 초기화해주고 call _syscall 해준다
c언어로 피라미드를 만들어보면
#include <stdio.h>
int main(void) {
int n = 7, i, j;
for(int i = 0; i < n; i++) {
for(int j = 0; j <= i; j++) {
printf("*");
}
}
for(int i = n-1; i > 0; i--) {
for(int j = 0; j < i; j++) {
printf("*");
}
printf("\n");
}
return 0;
}
피라미드 올라가는 부분 내려가는 부분으로 크게 두가지로 나눌 수 있다
이것을 어셈블리어로 만들어보자
n으로 높이 설정해주고 i는 큰 반복문 j는 작은 반복문
n = r8, i = r9, j = r10
section .data
STAR db '*'
EMPTY db 0x0a
section .text
global _start
_start:
mov rax, 1
mov rdi, 1
mov rdx, 1
mov r10, 0
mov r9, [rsp +16]
cmp r9, 0
je _done
mov cl, [r9]
movzx r9, cl
sub r9, 0x30
mov r8, r9
xor r9, r9
call _syscall
_small:
cmp r10, r9
je _up
mov rsi, STAR
syscall
mov rax, 1
inc r10
jmp _small
_up:
cmp r9, r8
je _down
mov rsi, EMPTY
syscall
mov rax, 1
mov r10, 0
add r9, 1
jmp _small
_down:
cmp r9, 0
je _down;
mov rsi, EMPTY
syscall
mov rax, 1
mov r10, 0
add r9, 1;
jmp _big
_big:
cmp r10, r9
je _down
mov rsi, STAR
syscall
mov rax, 1
inc r10
jmp _big
_done
mov rax, 60
mov rdi, 0
syscall
_syscall:
syscall
ret
r10과 r9를 비교해서 i번 출력한 경우 _up 함수를 불러오게 함
rsi에 STAR를 담아 별을 출력할 수 있게 함
syscall로 출력하고 rax 1로 설정하여 write 시스템 콜 설정 왜냐하면 출력된 결과가 rax에 담기기 때문에 다시 출력문으로 바꿔주려면 다시 설정해야함
inc r10 으로 j를 1증가시킴 그리고 jmp small 로 자기자신을 다시 불러오는 것
_up 함수를 만들고 cmp r9, r8 은 i==n이 된 경우
즉 다 채웠다면 다시 내려가는 함수인 _down을 불러준다
만약 내려가지않고 i가 n보다 작다면 rsi에 EMPTY를 담아서 줄바꿈을 실행 syscall을 해서 실제로 줄바꿈을 해줄 수 있게 함
그 후 다시 rax에 1을 설정해주어서 출력모드로 바꿈
j를 0으로 해주고 i에 1을 더해줌 그리고 _small로 점프
_done 함수를 만들어주고 rax에 60 rdi에 0을 넣고 syscall해주고
_syscall 함수에는 syscall과 ret를 넣는다
내려가는 것도 만들어주고 파일을 만들어주고 하면 제대로 동작한다