[c] GCC 패드가 NOP와 함께 작동하는 이유는 무엇입니까?

나는 C와 잠시 동안 일 해왔고 아주 최근에 ASM에 들어가기 시작했습니다. 프로그램을 컴파일 할 때 :

objdump 디스 어셈블리에는 코드가 있지만 ret 후에는 nops입니다.

내가 배운 것에서 nops는 아무것도하지 않으며 이후 ret은 실행되지 않을 것입니다.

내 질문은 : 왜 귀찮게? ELF (linux-x86)는 어떤 크기의 .text 섹션 (+ main)에서도 작동하지 않습니까?

도움을 주시면 감사하겠습니다.



답변

우선, gcc항상 이렇게하는 것은 아닙니다. 패딩은에 의해 제어 -falign-functions되며 -O2및 에 의해 자동으로 설정됩니다 -O3.

-falign-functions
-falign-functions=n

함수의 시작 부분을보다 큰 다음 2의 제곱 n에 맞추고 n바이트 까지 건너 뜁니다 . 예를 들어
-falign-functions=32는 다음 32 바이트 경계에 함수를 정렬하지만 -falign-functions=2423 바이트 이하를 건너 뛰어 수행 할 수있는 경우에만 다음 32 바이트 경계에 정렬합니다.

-fno-align-functions-falign-functions=1동일 기능과 정렬되지 않는다는 것을 의미한다.

일부 어셈블러는 n이 2의 거듭 제곱 일 때만이 플래그를 지원합니다. 이 경우 반올림됩니다.

n이 지정되지 않았거나 0이면 시스템 종속 기본값을 사용하십시오.

-O2, -O3 수준에서 활성화됩니다.

여러 가지 이유가있을 수 있지만 x86의 주요 이유는 다음과 같습니다.

대부분의 프로세서는 정렬 된 16 바이트 또는 32 바이트 블록으로 명령어를 가져옵니다. 코드에서 16 바이트 경계 수를 최소화하기 위해 중요 루프 항목과 서브 루틴 항목을 16 씩 정렬하는 것이 유리할 수 있습니다. 또는 중요한 루프 항목 또는 서브 루틴 항목 이후 처음 몇 개의 명령어에 16 바이트 경계가 없는지 확인하십시오.

(Agner Fog의 “어셈블리 언어에서 서브 루틴 최적화”에서 인용)

편집 : 다음은 패딩을 보여주는 예입니다.

기본 설정으로 gcc 4.4.5를 사용하여 컴파일하면 다음과 같은 결과가 나타납니다.

지정 -falign-functions하면 다음이 제공됩니다.


답변

이것은 다음 함수를 8, 16 또는 32 바이트 경계로 정렬하기 위해 수행됩니다.

A.Fog의 “어셈블리 언어에서 서브 루틴 최적화”에서 :

11.5 코드 정렬

대부분의 마이크로 프로세서는 정렬 된 16 바이트 또는 32 바이트 블록으로 코드를 가져옵니다. 중요한 서브 루틴 항목 또는 점프 레이블이 16 바이트 블록의 끝 근처에있는 경우 마이크로 프로세서는 해당 코드 블록을 가져올 때 몇 바이트의 유용한 코드 만 가져옵니다. 레이블 뒤의 첫 번째 명령어를 디코딩하려면 다음 16 바이트도 가져와야 할 수 있습니다. 이것은 중요한 서브 루틴 항목과 루프 항목을 16으로 정렬하여 피할 수 있습니다.

[…]

서브 루틴 항목을 정렬하는 것은 원하는대로 주소를 8, 16, 32 또는 64로 나눌 수 있도록 서브 루틴 항목 앞에 필요한만큼 많은 NOP를 넣는 것만 큼 간단합니다.


답변

내가 기억하는 한 명령어는 cpu에서 파이프 라인되고 다른 cpu 블록 (로더, 디코더 등)은 후속 명령어를 처리합니다. RET명령이 실행될 때 다음 명령이 이미 cpu 파이프 라인에로드되지 않습니다. 추측이지만 여기에서 파헤 치기 시작할 수 있습니다. 그리고 만약 당신이 알아 내면 (아마도 NOP안전한 s 의 특정 수 , 당신의 발견을 공유하십시오.


답변