프로그래밍/C

C 배열 포인터 array VS &array 차이, 디버깅을 통한 확인

msh1307 2022. 5. 22. 19:05
1
2
3
4
5
6
7
#include <stdio.h> 
int main(){
    int arr[10]={1,2,3,4,5,6,};
    printf("%p %p",arr,&arr);
    return 0;
}
 
 
cs

위와 같은 코드를 입력하고 돌려보면, 

위와 같은 주소를 확인할 수 있다. 

여기서 둘 다 같은 주소를 얻을 수 있으니, 같다고 생각하기 쉽다. 

1
2
3
4
5
6
#include <stdio.h> 
int main(){
    int arr[10]={1,2,3,4,5,6,};
    printf("%p %p",arr+1,&arr+1);
    return 0;}
}
 
cs

조금 수정해서 다시 돌려보면, 차이를 알 수 있다.

기본적으로 C언어에서 포인터에 연산을 해주면, 형에 따라서 가중치만큼 더하거나 빼준다. 

int형의 경우에는 +1을 하면 일반적으로 4바이트를 더한다. 

둘의 출력 결과가 다른 것을 확인할 수 있다. 

그냥 &arr과 &arr+1의 주소 값의 차이는 40이다. 

이렇게 차이가 생기는 이유는 arr가 기본적으로 배열의 첫 번째 원소에 대한 포인터를 의미하고, &arr가 배열 전체에 대한 포인터를 의미하기 때문이다.

여기선 배열의 원소가 10개이므로 4*10인 40이 더해지게 된 것이다. 

1
2
3
4
5
6
7
#include <stdio.h> 
int main(){
    int arr[10]={1,2,3,4,5,6,};
    printf("%p %p",(int *)arr+1,(int *)&arr+1);
    return 0;
}
 
 
cs

이렇게 포인터 타입 캐스팅을 int로 해주거나 void 같은 것으로 바꿔주면 사실 의미 자체는 크게 달라지지 않는다. 

gdb로 한번 열어보면 더 자세히 알 수 있다. 

vim으로 똑같이 작성하고 열어봤다.

이미 pwndbg는 깔아둔 상태이다.

어셈블리 코드만 보더라도 알 수 있다. 

rdx에 rbp-0x30의 주소 값을 넣어서 배열의 첫 번째 원소의 주소를 넣어준다. 

그다음 따로 0x28을 더해서 rdx에 들어가게 된다.

rsi에는 rbp-0x30의 주소값에서 0x4만큼 따로 더해져서 들어가는 것을 확인할 수 있다.

64비트 환경이기 때문에 파라미터 전달을 rdi rsi rdx 순서로 레지스터로 전달해준다. 

rdi는 문자열, rsi는 arr+1, rdx는 &arr+1이 될 것이다. 

 

printf@plt를 call하기 직전에 걸어보겠다.

rdi rsi rdx 레지스터의 값을 읽어보겠다. 

rdi에 제대로 문자열이 들어가있다.

rsi, rdx는 둘의 주소값이다.