GCC 패드는 왜 NOP에서 기능합니까?
저는 C와 잠시 일하다가 ASM에 입사한 지 얼마 되지 않았습니다.프로그램을 컴파일할 때:
int main(void)
{
int a = 0;
a += 1;
return 0;
}
objdump disassembly에는 코드가 있지만 재시도 후 nop:
...
08048394 <main>:
8048394: 55 push %ebp
8048395: 89 e5 mov %esp,%ebp
8048397: 83 ec 10 sub $0x10,%esp
804839a: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp)
80483a1: 83 45 fc 01 addl $0x1,-0x4(%ebp)
80483a5: b8 00 00 00 00 mov $0x0,%eax
80483aa: c9 leave
80483ab: c3 ret
80483ac: 90 nop
80483ad: 90 nop
80483ae: 90 nop
80483af: 90 nop
...
내가 배운 바로는 nops는 아무 것도 안 하고, ret 후에도 실행이 안 되거든.
내 질문은 왜 귀찮게 하느냐는 것이다.ELF(linux-x86)는 어떤 크기의 .text 섹션(+main)에서도 사용할 수 없습니까?
어떤 도움이라도 주시면 고맙겠습니다. 그저 배우려고 노력했을 뿐입니다.
일단은...gcc
항상 이런 건 아니에요패딩은 에 의해 제어되며 에 의해 자동으로 설정됩니다.-O2
그리고.-O3
:
-falign-functions
-falign-functions=n
함수의 시작을 다음 2의 제곱보다 큰 값으로 맞춘다.
n
까지 건너뛰다n
바이트. 예를 들어,-falign-functions=32
다음 32바이트 경계에 함수를 정렬합니다.-falign-functions=24
23바이트 이하로 건너뛸 수 있는 경우에만 다음 32바이트 경계에 맞춥니다.
-fno-align-functions
그리고.-falign-functions=1
는 동일하며 함수가 정렬되지 않음을 나타냅니다.일부 어셈블러는 n이 2의 거듭제곱일 때만 이 플래그를 지원합니다.이 경우 반올림됩니다.
n이 지정되지 않았거나 0인 경우 시스템에 의존하는 기본값을 사용합니다.
레벨 -O2, -O3에서 유효합니다.
여기에는 여러 가지 이유가 있을 수 있지만 x86의 주된 이유는 다음과 같습니다.
대부분의 프로세서는 정렬된 16바이트 또는 32바이트 블록으로 명령을 가져옵니다.코드 내의 16바이트 경계 수를 최소화하기 위해 크리티컬루프 엔트리와 서브루틴 엔트리를 16으로 정렬하는 것이 유리할 수 있습니다.또는 크리티컬루프 엔트리 또는 서브루틴 엔트리 뒤에 처음 몇 가지 명령에 16바이트의 경계가 없는지 확인합니다.
(Agner Fog의 "어셈블리 언어로 서브루틴 최적화"에서 인용)
edit: 패딩을 나타내는 예를 다음에 나타냅니다.
// align.c
int f(void) { return 0; }
int g(void) { return 0; }
기본 설정으로 gcc 4.4.5를 사용하여 컴파일하면 다음과 같이 표시됩니다.
align.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <f>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: b8 00 00 00 00 mov $0x0,%eax
9: c9 leaveq
a: c3 retq
000000000000000b <g>:
b: 55 push %rbp
c: 48 89 e5 mov %rsp,%rbp
f: b8 00 00 00 00 mov $0x0,%eax
14: c9 leaveq
15: c3 retq
지정-falign-functions
다음과 같은 기능이 있습니다.
align.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <f>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: b8 00 00 00 00 mov $0x0,%eax
9: c9 leaveq
a: c3 retq
b: eb 03 jmp 10 <g>
d: 90 nop
e: 90 nop
f: 90 nop
0000000000000010 <g>:
10: 55 push %rbp
11: 48 89 e5 mov %rsp,%rbp
14: b8 00 00 00 00 mov $0x0,%eax
19: c9 leaveq
1a: c3 retq
이는 8, 16 또는 32바이트 경계에 따라 다음 함수를 정렬하기 위해 수행됩니다.
A의 "어셈블리 언어로 서브루틴 최적화"에서.안개:
11.5 코드의 정렬
대부분의 마이크로프로세서는 정렬된 16바이트 또는 32바이트 블록으로 코드를 가져옵니다.importantsubroutine 엔트리 또는 점프라벨이 16바이트 블록의 끝에 있는 경우 주제 프로세서는 코드 블록을 가져올 때 유용한 코드 바이트를 몇 개만 가져옵니다.라벨 뒤에 있는 첫 번째 명령을 디코딩하기 전에 다음 16바이트를 가져와야 할 수도 있습니다.이는 중요한 서브루틴엔트리와 루프엔트리를 16으로 정렬함으로써 회피할 수 있습니다.
[...]
서브루틴 엔트리를 정렬하는 것은 서브루틴 엔트리 앞에 필요한 수의 NOP를 배치하여 필요에 따라 주소를 8, 16, 32 또는 64로 분할할 수 있도록 하는 것만으로 간단합니다.
제 기억으로는 명령어는 cpu에 파이프라인 처리되어 있으며 다른 cpu 블록(로더, 디코더 등)은 후속 명령어를 처리합니다.RET
이치노다음 명령어가 CPU 파이프라인에 로드되어 있는 경우는 거의 없습니다. 됩니다.그리고 만약 당신이 알게 된다면 (아마도 구체적인 숫자는)NOP
안전하다고 생각되면 결과를 공유해 주세요.
언급URL : https://stackoverflow.com/questions/7912464/why-does-gcc-pad-functions-with-nops
'programing' 카테고리의 다른 글
Vue cli 3 및 IE 11 (0) | 2022.07.03 |
---|---|
Java 속성 파일 사용 방법 (0) | 2022.07.03 |
Vuex에서 여러 namesled 모듈을 호출하는 방법 (0) | 2022.07.03 |
Firefox 또는 Chrome 72 이상에서 SVG 데이터 이미지가 작동하지 않음 (0) | 2021.01.18 |
Jenkinsfile에서 빌드 실패 (0) | 2021.01.18 |