#include <stdio.h>
int main() {
printf("hello world\n");
}
$ gcc -o no-pie test.c -no-pie
$ gcc -o default test.c
$
$ readelf -a ./no-pie | grep "NOW"
$
$ readelf -a ./default | grep "NOW"
0x000000000000001e (FLAGS) BIND_NOW
0x000000006ffffffb (FLAGS_1) Flags: NOW PIE
$
$
no-pie 옵션과 바인딩의 연관성을 검색하던 중에
$ strings `which gcc` | grep "\-z now"
... %{static|shared|r:;!no-pie:-pie -z now} ...
위와 같은 옵션을 발견했습니다. no-pie 옵션이 없을 때 "-pie -z now" 옵션을 추가해주는데 -pie는 그렇다 쳐도 -z now를 추가해주는 이유를 모르겠습니다
pie를 사용하지 않을 때 lazy-binding을 사용하면 성능상, 보안상의 이점이 따로 있을까요?
두개가 연관성이 있나요...? 잘 모르겠네요... 제가 볼땐 별개인 것 같은데...
now bind는 바이너리가 실행될때 libc 내 주소를 got에 가져오고
lazy bind는 함수가 실행될때 가져오는 차이가 있고
pie는 쉽게 말해서 코드 영역의 aslr인데
둘의 연관성이 있는지 잘 모르겠습니다.
다만, 아래 링크와 같이 우분투에서는 디폴트 옵션으로 된 부분이 있다고 하네요.
https://stackoverflow.com/questions/62527697/why-does-gcc-link-with-z-now-by-default-although-lazy-binding-is-the-default
그러므로 마지막에 질문하신 부분은 연계해서 고려해야하는 것이 아니라 별개로 봐야될 것 같습니다.
제가 질문의 의도를 파악하지 못하고 있었네요.
말씀하신 것과 같이 데비안에서 '권장하는' 컴파일 옵션이 설명해주신 부분인 것 같습니다.
권장한다는 것은 곧 보안이나 속도를 위한 최소한의 요건들을 경험적으로 판단하여 설정해둔 것이라 생각합니다.
저기서 조금 빠진 부분이 있는데 바로 relro 입니다.
링크해주신 부분 이외에 다른 곳에서 설정되는 것 같네요.
즉, now와 함께 relro가 기본 옵션으로 들어갑니다.
기본 옵션의 경우 아무 소스코드나 만드신 이후에
gcc --verbose 파일명
과 같이 실행해보시면 확인하실 수 있습니다.
relro가 들어가면서 왜 now가 pie와 함께 쓰였는지 이해되실거라 생각합니다.