arm64 architecture instruction

와… armop 문제를 풀면서 정말 많은 일이 있었으나 arm64는 처음이라 더 힘들었다.

일단 스택 배열과 함수에서 쓰이는 명령어들이 너무 생소해서 놀랐다.

함수의 오프닝

C
0x00000000004007d4 <+0>:	stp	x29, x30, [sp, #-16]!

stp는 Store pair register라는 뜻이다. 즉, str은 1개의 레지스터 값을 저장하는 반면 stp는 두개의 레지스터를 저장한다. 저장하는 위치는 뒤에 있는 [sp, #-16] 즉, sp레지스터의 값 -16 의 위치에 저장한다.

함수의 엔딩

C
 0x0000000000400838 <+100>:	ldp	x29, x30, [sp], #16

ldp는 load pair register 이다. 역시 ldr에 2개 버전이며, sp레지스터 값의 주소로 부터 x29, x30 레지스터 2개를 읽어온다. 즉, 8바이트 + 8바이트 를 읽어 온다.그리고 #16은 sp에 +16 을 해서 스택을 닫는다는 의미이다.

그럼 여기서 x29 , x30 이 뭐냐고 물어볼 수 있다. x29는 rbp랑 유사한 개념인데 단순 디버깅용이다. 즉, 전혀 실제적인 sp 레지스터에 영향을 끼치지 못한다. 따라서 최적화에 따라 없어질 수 있다.

반면에 x30 레지스터는 link reg로 ret 명령어를 만나면 x30 레지스터 값을 pc 값에 넣는다.

여기까지 보면 익숙한 배치이다. x86-64에서는 pop , push 의 개념이 ldr(ldp) , str(stp) 으로 바뀌었다고 생각하면 된다.

그럼 이러한 것을 생각하면 이제 arm64는 어떤 스택 구조를 가질까?

다음과 같은 구조를 가진다. 앞서 말했듯이 rbp는 영향이 없는 값이다.

지금 보면 일단 x86 , x64 와는 다르게 rbp의 개념이 없다. 따라서 sp 만 존재하는데

sp 쪽에 rbp와 RA가 위치한다. 그리고 그 이후에 local ( 지역 변수 )들이 위치한다. 따라서 bof가 일어나도 해당 함수의 RA를 덮어 쓸 수 없고 이전 함수의 RA를 덮어써야 한다.