programing

GCC 패드는 왜 NOP에서 기능합니까?

minecode 2022. 7. 3. 00:09
반응형

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=2423바이트 이하로 건너뛸 수 있는 경우에만 다음 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

반응형