programing

컴파일러에서 함수 이름 앞에 밑줄이 붙는 이유는 무엇입니까?

skycolor 2023. 6. 21. 22:27
반응형

컴파일러에서 함수 이름 앞에 밑줄이 붙는 이유는 무엇입니까?

C 앱의 어셈블리 코드를 보면 다음과 같습니다.

emacs hello.c
clang -S -O hello.c -o hello.s
cat hello.s

함이앞는밑예줄에름수)이.callq _printf은 왜 ?) 이것은 왜 행해지고 어떤 이점을 가지고 있습니까?


예:

안녕하세요.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main() {
  char *myString = malloc(strlen("Hello, World!") + 1);
  memcpy(myString, "Hello, World!", strlen("Hello, World!") + 1);
  printf("%s", myString);
  return 0;
}

안녕하세요.

_main:                       ; Here
Leh_func_begin0:
    pushq   %rbp
Ltmp0:
    movq    %rsp, %rbp
Ltmp1:
    movl    $14, %edi
    callq   _malloc          ; Here
    movabsq $6278066737626506568, %rcx
    movq    %rcx, (%rax)
    movw    $33, 12(%rax)
    movl    $1684828783, 8(%rax)
    leaq    L_.str1(%rip), %rdi
    movq    %rax, %rsi
    xorb    %al, %al
    callq   _printf          ; Here
    xorl    %eax, %eax
    popq    %rbp
    ret
Leh_func_end0:

링커로더에서:

1974년쯤 UNIX가 C에서 다시 작성되었을 때, UNIX의 작성자들은 이미 광범위한 어셈블리어 라이브러리를 가지고 있었고, 새로운 C와 C 호환 코드의 이름을 뒤로 돌아가서 모든 기존 코드를 수정하는 것보다 더 쉬웠습니다.20년이 지난 지금, 어셈블러 코드는 모두 5번 다시 작성되었고, UNIX C 컴파일러, 특히 COFF와 ELF 객체 파일을 만드는 컴파일러는 더 이상 밑줄을 추가하지 않습니다.

C 컴파일의 어셈블리 결과에 밑줄을 추가하는 것은 해결책으로 발생한 이름맹그 규칙일 뿐입니다.그것은 (제가 아는 한) 특별한 이유 없이 주변에 머물렀고, 지금은 클랑으로 진출했습니다.

어셈블리 외부에서 C 표준 라이브러리는 종종 마법의 개념을 전달하고 이를 우연히 발견한 일반 프로그래머에게 건드리지 않기 위해 밑줄이 붙은 구현 정의 함수를 가지고 있습니다.

많은 컴파일러들이 C를 어셈블리 언어로 변환하고, 그 위에서 어셈블리어를 실행하여 객체 파일을 생성하는 데 사용되었습니다.바이너리 코드를 직접 생성하는 것보다 훨씬 쉽습니다.(AFAIK GCC는 여전히 이를 수행합니다.하지만 자체 조립기도 있습니다.)이 변환 중에 함수 이름은 어셈블리 소스의 레이블이 됩니다.를 들어) (으)라는 기능이 있다면, (으)ㄹ 수 .ret하만지, 일부조은혼동수그라있것벨수생다있니습각할아고 (은 라벨이 콜론을 로 하지 않기예를 들어 YASM은 레이블이 거의 모든 위치에 나타날 수 있고 콜론이 필요하지 않기 때문에 대부분 그렇습니다. 앞에 .$만약 당신이 라벨을 원한다면.ret.)

C 생성 레이블에 문자(예: 밑줄)를 추가하는 것은 자신의 C 친화적인 어셈블리어를 작성하거나 레이블이 어셈블리 지침/지시와 충돌할 것을 걱정하는 것보다 훨씬 쉬웠습니다.

요즘은 어셈블러와 컴파일러가 조금 발전했고, 어쨌든 대부분의 사람들은 C 레벨 이상에서 일합니다.따라서 C에서 이름을 망치는 원래의 필요성은 거의 사라졌습니다.

언뜻 보기에 운영 체제는 PC에서 실행되는 Unix/Unix와 유사합니다.제 말에 따르면 생성된 어셈블리 언어에서 _printf를 찾는 것은 그리 놀라운 일이 아닙니다.Cprintf는 I/O를 수행하는 기능입니다.따라서 요청된 I/O를 수행하는 것은 커널 + 드라이버의 책임입니다.

모든 유닉스/유닉스 계열 OS에서 사용되는 기계 명령 경로는 다음과 같습니다.

printf (C code) -> _printf (libc) -> trap -> 커널 + 드라이버 작업 -> 트랩에서 반환 -> _printf (libc) -> printf 완료에서 반환 -> C 코드의 다음 기계 명령어

이 어셈블리 코드 추출물의 경우 컴파일러에 의해 C printf가 인라인화되어 어셈블리 코드에 _printf 진입점이 표시되는 것처럼 보입니다.

C printf가 접두사(이 경우 밑줄)로 장식되지 않도록 하려면 모든 C 헤더에서 다음과 같은 명령을 사용하여 _printf를 검색하는 것이 가장 좋습니다.

/usr/adm -name *.h -execgrep _printf {} \; -print를 찾습니다.

언급URL : https://stackoverflow.com/questions/5908568/what-is-the-reason-function-names-are-prefixed-with-an-underscore-by-the-compile

반응형