일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- OS
- assembly
- modr/m
- csproj
- load effective address
- WPF
- disassemble
- GCC
- movdqu
- void main
- movaps
- compare
- NASM
- C
- C#
- 운영체제
- modrm
- movups
- effective address
- return
- struct
- stackalign
- 어셈블리
- sib
- instruction
- struct반환
- C언어
- call instruction
- 숏코딩
- 유효 주소
- Today
- Total
프로그래밍 잡화점
struct 반환에 대한 고찰 본문
예전이 이런 포스팅을 한적이 있었다.
어셈블리를 사용하면서 얻은 지식이 있어 추가적으로 보완하고자 글을 쓰게 되었다.
struct를 반환하게 되면 어셈블리에선 어떠한 일이 일어나는가? 에 대해서 알아보도록 하자
일단 먼저 struct는 레지스터에 들어갈 수 있는 크기가 아니다 보니 값 그 자체로 반환되지는 않는다.
보통 struct를 반환하는 함수 내에서 어딘가에는 struct를 선언하는 코드가 존재한다. 즉, 해당 함수 내의 스택에 struct크기 만큼의 공간을 확보해둔다는 의미이다.
이제 return하는 시점으로 돌아와 보자.
return을 하게 되면 보통 다음과 같이 호출자에서 반환된 struct를 받아 할당하게 된다
struct Point {
int x, y;
}
Point getPoint() {
Point p;
// Do something
return p;
}
int main() {
Point p = getPoint();
}
(대충 알아볼 수 있게 코드를 짰으니 문법 오류와 관련한 이야기는 넘어가도록 하자)
struct를 반환할 때에는 함수 내에 스택에 선언된 struct의 포인터를 반환한다.
즉, rax(eax)에 들어가는 값은 호출한 함수의 스택에 선언되어 있는 struct를 가리키는 것이란 소리이다.
저 코드를 예시로 어셈블리로 봐보자.
section .text
(생략...)
getPoint:
push ebp
mov ebp, esp
; Point크기 만큼 스택 할당
sub esp, 8
; Do something
lea eax, [ebp-8]
leave
ret
main:
push ebp
mov ebp, esp
; Point크기 만큼 스택 할당
sub esp, 8
call getPoint
mov ebx, [eax]
mov [ebp-8], ebx
mov ebx, [eax+4]
mov [ebp-4], ebx
(생략...)
이러한 식으로 동작할 수 있다는 얘기이다.
여기서 하나 알고 넘어가야 할 점은, 반환된 포인터가 가리키는 위치이다.
보통 반환된 포인터가 가리키는 위치는 struct의 맨 첫번째 값이다.
위 예제에선 Point.x 가 될 것이다. 그 뒤로 순서대로 바이트가 증가하는 구조를 갖는다.
그럼 여기서 의문점이 든다.
"함수 호출 후 ret으로 빠져나오면 함수의 스택이 정리되게 되며 이 공간은 다른 데이터에 의해 오염될 가능성이 있지 않나요?"
이 내용도 틀린 내용은 아니다.
그러나 우리가 주의 깊게 봐야 할 것은 함수 호출 후 호출자에서 Point sturct를 선언하여 할당 받고 있다는 것이다.
함수가 종료되어도 프로그램은 해당 함수가 사용했던 곳을 0으로 채우거나 값을 변경하지 않는다.
따라서 함수가 종료된 이후에 받은 포인터를 통해서 호출자의 스택에 해당 포인터의 값을 옮기는 방식을 사용할 수 있는 것이다.
다만, 호출하기 전 미리 공간 할당을 해놓은 상태여야 한다.
C에선 편하게 사용되는 것들이 어셈블리에선 복잡한 기능으로 얽혀있는 경우가 종종 있다.
struct도 예외는 아니다.
여담으로,
struct 반환에 대해서 이해가 갈때 쯤 드는 의문이 하나 있다.
"그렇다면 struct* 의 반환은 어떻게 될까?"
참 재밌게도 struct와 struct*모두 struct의 위치를 갖는 포인터를 반환한다.
'C, C++ 분석 보고서' 카테고리의 다른 글
함수의 반환에 대한 고찰 (0) | 2022.12.27 |
---|---|
main의 반환형에 관한 고찰 (In C) (2) | 2022.05.04 |
if에 관한 고찰 (In C) (0) | 2022.03.13 |
bool과 int의 관계 (In C) (0) | 2022.03.12 |
for에 관한 작은 고찰 (In C) (0) | 2022.03.11 |