컴파일러가 어셈블리 코드를 생성하는 이유는 무엇입니까?


19

어셈블리 언어는 어셈블러에 의해 기계 언어로 변환됩니다. 컴파일러가 고급 언어를 어셈블리로 변환하는 이유는 무엇입니까? 고급 언어에서 기계 코드로 직접 변환 할 수 없습니까?

답변:


22

컴파일러가 적절한 머신 코드가 아닌 어셈블리를 생성하는 다른 이유는 다음과 같습니다.

  • 하드 코딩 머신 주소 대신 어셈블러에서 사용되는 기호 주소는 코드 재배치를 훨씬 쉽게 해줍니다.
  • 코드 연결 에는 유형 검사와 같은 안전 검사가 필요할 수 있으며 기호 이름으로 수행하기가 더 쉽습니다.
  • 코드 생성기 대신 어셈블러를 변경하면 기계 코드를 조금만 변경해도 쉽게 수용 할 수 있습니다.

왜 어셈블리 언어가 그렇게 효율적인지, 영어로 작성되었지만 프로세서가 어떻게 그것을 이해합니까?
CODERSAM

3
@CODERSAM Assembly는 자연어가 아닌 공식 언어입니다. 기계 언어에 매우 가깝습니다. 따라서 번역은 비 효율성을 초래하지 않습니다.
Martin Berger

"기계 언어에 매우 가깝다"고 말할 때 그 의미는 무엇입니까? 나는 정말로 이것과 혼동된다!
CODERSAM

2
@CODERSAM 정확한 의미는 복잡하지만 대수학에서 동질성 같은 것입니다. 번역 할 때 x86 어셈블리 인 "add eax, # 2"라고 말하면 더 이상 내용을 추가하지 않고도 컨텍스트를 보지 않고도 d7f5 (또는 op 코드가 될 수있는 다른 것)로 바로 번역 할 수 있습니다. 어셈블리에는 추상화가 없습니다.
Martin Berger

1
"어셈블리에는 추상화가 없습니다"— 레이블 이름은 이미 오프셋 (offset)에서 추상화 된 것입니다. 또한, 컨텍스트 역할을 수행합니다 예를 들어가 add eax,2로 번역 될 수 있습니다83 c0 0266 83 c0 02 들어와 같이 최근에 발생한 지시문에 따라 또는로use16 .
Ruslan

15

컴파일러는 일반적으로 고급 코드를 기계 언어로 직접 변환하지만 모듈 식 방식으로 빌드하여 하나의 백엔드에서 기계 코드와 다른 어셈블리 코드 (예 : GCC)를 생성 할 수 있습니다. 코드 생성 단계는 기계어 코드의 내부 표현 인 "코드"를 생성 한 다음 기계어 또는 어셈블리 코드와 같은 사용 가능한 형식으로 변환해야합니다.


또한 소스에 일부 어셈블리 코드가 포함 된 경우 어쨌든 해당 인라인 어셈블리를 변환하는 메커니즘을 사용할 수 있어야합니다.
Paul A. Clayton

왜 어셈블리 언어가 그렇게 효율적인지, 영어로 작성되었지만 프로세서가 어떻게 그것을 이해합니까?
CODERSAM

1
어셈블리 언어는 기계 코드에 대한 "영어"설명입니다.
유발 Filmus

11

역사적으로 많은 유명한 컴파일러가 기계 코드를 직접 출력했습니다. 그러나 그렇게하는 데 어려움이 있습니다. 일반적으로 컴파일러가 올바르게 작동하는지 확인하려고하는 사람은 머신 코드보다 어셈블리 코드 출력을 쉽게 검사 할 수 있습니다. 또한, 1 패스 C 또는 파스칼 컴파일러를 사용하여 어셈블리 언어 파일을 생성 한 다음 2 패스 어셈블러를 사용하여 처리 할 수 ​​있습니다. 코드를 직접 생성하려면 2 패스 C 또는 Pascal 컴파일러를 사용하거나 단일 패스 컴파일러를 사용하고 정방향 점프 주소를 백패 칭하는 방법이 필요합니다 (런타임 환경에서 시작된 프로그램의 크기를 고정 점 컴파일러는 코드 끝에 패치 목록을 작성하고 시작 코드가 런타임에 해당 패치를 적용하도록 할 수 있습니다. 이러한 접근 방식은 실행 파일 크기를 패치 포인트 당 약 4 바이트 씩 증가 시키지만 프로그램 생성 속도를 향상시킵니다.

목표가 빠르게 실행되는 컴파일러를 갖는 것이면 직접 코드 생성이 효과적 일 수 있습니다. 그러나 대부분의 프로젝트에서 어셈블리 언어 코드를 생성하고 조립하는 비용은 오늘날 큰 문제가되지 않습니다. 컴파일러가 다른 컴파일러에 의해 생성 된 코드와 잘 상호 작용할 수있는 형태로 코드를 생성하게하는 것은 일반적으로 컴파일 시간의 증가를 정당화 할 수있는 큰 이점입니다.


1

동일한 명령어 세트를 사용하는 플랫폼조차도 재배치 가능한 객체 파일 형식이 다를 수 있습니다. "a.out"(이전의 UNIX), OMF, MZ (MS-DOS EXE), NE (16 비트 Windows), COFF (UNIX System V), Mach-O (OS X 및 iOS) 및 32 비트 Windows에서 ELF (Linux 및 기타)와 XCOFF (AIX), ECOFF (SGI) 및 COFF 기반 PE (Portable Executable)와 같은 변형이 있습니다. 어셈블리 언어를 생성하는 컴파일러는 객체 파일 형식에 대해 많이 알 필요가 없으므로 어셈블러와 링커가 해당 지식을 별도의 프로세스로 캡슐화 할 수 있습니다.

스택 오버플로에서 OMF와 COFF의 차이점을 참조하십시오 .


1

일반적으로 컴파일러는 일련의 명령어로 내부적으로 작업합니다. 각 명령어는 연산 이름, 피연산자 등을 나타내는 데이터 구조로 표시됩니다. 피연산자가 주소 인 경우 해당 주소는 일반적으로 구체적인 값이 아닌 기호 참조입니다.

출력 어셈블러는 비교적 간단합니다. 컴파일러 내부 데이터 구조를 가져 와서 특정 형식의 텍스트 파일로 덤프하는 것이 중요합니다. 어셈블러 출력도 비교적 읽기 쉽고 컴파일러가 수행하는 작업을 확인해야 할 때 유용합니다.

이진 객체 파일을 출력하는 것이 훨씬 더 많은 작업입니다. 컴파일러 작성자는 모든 명령어가 어떻게 인코딩되는지를 알아야합니다 (일부 CPU에서는 그다지 중요하지 않음). 일부 심볼릭 참조를 프로그램 카운터 상대 주소로, 다른 것은 이진 객체 파일의 메타 데이터 형식으로 변환해야합니다. . 시스템에 매우 적합한 형식으로 모든 것을 작성해야합니다.

예, 중간 단계로 어셈블러를 작성하지 않고도 이진 객체를 직접 출력 할 수있는 컴파일러를 만들 수 있습니다. 소프트웨어 개발에서 많은 것들과 같은 문제는 컴파일 시간 단축이 추가 개발 및 유지 보수 작업에 가치가 있는지 여부입니다.

내가 가장 잘 알고있는 컴파일러 (freepascal)는 모든 플랫폼에서 어셈블러를 출력 할 수 있지만 플랫폼의 하위 집합에서만 이진 객체 만 출력 할 수 있습니다.


1

컴파일러는 일반적인 재배치 가능 코드 외에도 프로그래머의 이익을 위해 어셈블러 출력을 생성 할 수 있어야합니다.

한 번은 LSI-11 시스템의 Unix System V에서 실행되는 C 프로그램에서 버그를 찾지 못했습니다. 아무것도 작동하지 않는 것 같습니다. 마지막으로 필사적 인 protable C 컴파일러는 어셈블러 버전의 번역을 배설했습니다. 나는 마침내 버그를 발견했다! 컴파일러가 머신에있는 것보다 많은 레지스터를 할당하고있었습니다! (컴파일러는 레지스터 R0 ~ R7 만있는 컴퓨터에서 레지스터 R0 ~ R8을 할당했습니다.) 컴파일러의 버그를 해결하고 프로그램이 작동했습니다.

어셈블러 출력의 또 다른 이점은 다른 매개 변수 전달 프로토콜을 사용하는 "표준"라이브러리를 사용하려는 것입니다. 나중에 C 컴파일러를 사용하면 매개 변수를 사용하여 프로토콜을 설정할 수 있습니다 ( "pascal"은 순서를 뒤집는 C 표준과 반대로 주어진 순서대로 컴파일러가 매개 변수를 추가하게합니다).

또 다른 이점은 프로그래머가 자신의 컴파일러가하는 일이 무엇인지 알 수있게 해줍니다. 간단한 C 문은 약 44 개의 기계 명령을 필요로합니다. 값은 메모리에서로드 된 후 빠르게 삭제됩니다. 등 등 ...

개인적으로 재배치 가능한 객체 모듈 대신 컴파일러를 사용하는 것이 실제로 어리석은 것이라고 생각합니다. 프로그램을 컴파일하는 동안 컴파일러는 프로그램에 대한 많은 정보를 수집합니다. 일반적으로이 모든 정보를 Symbol Table이라고하는 곳에 저장합니다. 어셈블러 코드를 배설 한 후이 모든 정보 테이블을 던집니다. 그런 다음 어셈블러는 배설 된 코드를 검사하고 컴파일러가 이미 가지고있는 일부 정보를 다시 수집합니다. 그러나 어셈블러는 For 문 또는 While 문의 If 문에 대해서는 아무것도 모릅니다. 따라서이 모든 정보가 없습니다. 그런 다음 어셈블러는 컴파일러가 수행 할 수없는 재배치 가능 객체 모듈을 생성합니다.

왜???

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.