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는 둘의 주소값이다.
'프로그래밍 > C' 카테고리의 다른 글
execve() argv 포인터 배열 확인 (0) | 2022.05.24 |
---|---|
C 함수 포인터, void 포인터 차이 (0) | 2022.05.22 |
size_t, pid_t,ssize_t... (0) | 2022.05.03 |
open, read 시스템콜을 이용한 파일 입출력 (0) | 2022.05.03 |
scanf, gets, fgets 차이 (0) | 2022.04.01 |