보근은 참고 있다
2.11 프로그램 번역과 실행 본문
컴파일러
컴파일러는 상위 수준 프로그램을 어셈블리 언어 코드로 바꾼다. 어셈블리 언어 프로그램은 컴퓨터가 이해할 수 있는 심벌 형태이다. 어셈블리 언어 프로그램에 비하면 상위 수준 프로그램의 문장 수는 훨씬 적다. 결국, 이 과정은 프로그래머의 생산성을 높여준다.
어셈블러
어셈블러는 어셈블리 언어 코드를 기계어 형태의 목적 모듈로 바꾼다. 어셈블리 언어는 상위 수준 프로그램과 기계어 사이의 인터페이스 역할을 한다. 이 명령어들은 하드웨어로 구현이 되어 있지 않더라도, 어셈블러가 알아서 처리하여 번역과 프로그래밍을 간편하게 해 준다. 이런 명령어들을 의사명령어(Pseudo instruction)이라 한다.
ex) move $t0, $t1 -> add $t0, $zero, $t1 // 기계어 명령어에는 move가 없으나 사용할 수 있게 해준다.
어셈블리 언어 프로그램의 각 명령어를 이진수로 바꾸기 위해선 레이블에 해당하는 모든 주소를 알아야 하는데, 어셈블러는 심벌 테이블(Symbol table)에 저장한다. 이 테이블은 심벌과 그 주소들을 저장한다.
어셈블리 언어 코드를 바꾼 기계어 형태의 목적 파일은 여섯 부분으로 구성된다.
- 목적 파일 헤더 : 목적 파일을 구성하는 각 부분의 크기와 위치를 서술한다.
- 텍스트 세그먼트 : 기계어 코드가 들어 있다.
- 정적 데이터 세그먼트 : 프로그램의 수명 동안 할당되는 데이터가 들어 있다.
- 재배치 정보 : 프로그램이 메모리에 적재될 때 절대 주소에 의존하는 명령어와 데이터 워드를 표시한다.
- 심벌 테이블 : 외부 참조같이 아직 정의되지 않고 남아 있는 레이블들을 저장한다.
- 디버깅 정보 : 각 모듈이 어떻게 번역되었는지에 대한 간단한 설명이 들어 있다.
링커
프로그램의 일부분이 수정될 때 마다 전체 프로그램을 컴파일하고 어셈블하면 자원 낭비가 심각해진다. 이것을 피하기 위해 수정된 프로시저만 다시 변역하게 도와주는 것이 링커(Linker) 또는 링크 에디터(Link editor)이다.
링커의 동작은 세 단계로 이뤄진다.
- 코드와 데이터 모듈을 메모리에 심벌 형태로 올려 놓는다.
- 데이터와 명령어 레이블의 주소를 결정한다.
- 외부 및 내부 참조를 해결한다.
로더
운영체제는 디스크에 있는 실행 파일을 메모리에 넣고 이를 시작시킨다. 디스크의 실행 파일을 메모리로 올려주는 것이 로더이다.
로더는 다음 여섯 단계로 실행한다.
- 실행 파일 헤더를 읽어서 텍스트와 데이터 세그먼트의 크기를 알아낸다.
- 텍스트와 데이터가 들어갈 만한 주소 공간을 확보한다.
- 실행 파일의 명령어와 데이터를 메모리에 복사한다.
- 주 프로그램에 전달해야 할 인수가 있으면 이를 스택에 복사한다.
- 레지스터를 초기화하고 스택 포인터는 사용 가능한 첫 주소를 가리키게 한다.
- 기동 루틴으로 점프한다. (이 기동 루틴에서는 인수를 인수 레지스터에 넣고 프로그램의 주 루틴을 호출한다. 주 프로그램에서 기동 루틴으로 복귀하면 exit 시스템 호출을 사용해 프로그램을 종료한다.)
동적 링크 라이브러리
정적 링크 라이브러리는 프로그램이 어셈블될 때 실행 코드의 일부가 된다. 라이브러리가 업그레이드 되거나, 업데이트 되어도 정적으로 링크된 프로그램은 구버전의 라이브러리를 사용해야 한다. 또, 이렇게 실행 코드의 일부가 된 라이브러리는 사용되지 않더라도 적재되어야 한다. 따라서 프로그램의 상당한 부분을 쓸데없이 차지하고 있을 수 있다.
이러한 단점들 때문에 동적 링크 라이브러리(DLL : Dynamically Linked Library)가 등장하였다. 이 방식에서는 프로그램 실행 전에는 라이브러리가 링크되지도 않고, 적재되지도 않는다. 대신 프로그램과 라이브러리 루틴은 전역적 프로시저의 위치와 이름에 대한 정보를 추가로 가지고 있다.
DLL을 호출하기 위해 간접 접근 기법을 사용한다. 이 과정은 프로그램 끝에 있는 더미 루틴(dummy routine)들을 호출하는 전역 루틴에서부터 시작된다. 라이브러리 루틴을 처음 호출할 때는 프로그램이 더미 루틴을 호출하고 더미 엔트리는 원하는 라이브러리 루틴을 표시하기 위해 레지스터에 숫자를 넣고 동적 링커/로더로 점프하는 코드를 가리킨다. 링커/로더는 원하는 루틴을 찾아서 재사상하고, 이 루틴을 가리키도록 간접 점프 위치에 있는 주소를 바꾼다. 그러고 나서는 그 주소로 점프한다. 이렇게 한 번 호출 후에는 다시 라이브러리 루틴을 호출해도 추가로 돌아다니는 일 없이 해당 루틴으로 간접 점프한다.
'CS > 컴퓨터 구조' 카테고리의 다른 글
2.17 오류 및 함정 (0) | 2020.10.14 |
---|---|
2.12 종합: C 정렬 프로그램 (0) | 2020.10.14 |
2.10 병렬성과 명령어: 동기화 (0) | 2020.10.14 |
2.9 MIPS의 32비트 수치를 위한 주소지정 및 복잡한 주소지정 방식 (0) | 2020.10.14 |
2.8 하드웨어의 프로시저 지원 (0) | 2020.10.14 |