Assembler
어셈블러의 역할
어셈블리어로 쓰인 원시 프로그램을 입력 받아
목적 프로그램(object file)을 생성하는 일을 한다.
어셈블러 task 의 정의
어셈블러는 명령어를 생성한다.
연산 기호를 보고 기계어 명령으로 번역하고
심볼과 literal에 주소를 할당한다.
어셈블러는 코드를 두 번 읽는다. (2 pass assembler)
심볼이 정의되지 않은 상태에서 참조(reference) 하는 경우
그 값을 알 수가 없다.
패스 1 : 각 기호의 값만을 결정, 심볼 테이블 결정 (레이블과 그 값들)
패스 2 : 목적 프로그램 생성
어셈블러 설계 - 패스 1
패스 1은 심볼을 정의한다.
- 각 기계어의 길이를 결정한다. (앞서 배웠듯, 명령어의 길이는 용도, 피연산자마다 다양)
- 위치 카운터, 즉 현재 처리하고 있는 명령어 주소의 증가.
(이는 분기 또는 함수 호출할 때 피연산자로 넣어줄 주소로 사용) - 심볼의 값을 기억한다.
자료구조
- 소스 프로그램
- 명령어 테이블 (명령어의 유형과 길이 정보)
- 삼볼 테이블
- LC
*인텔은 CISC 프로세서로, 명령어들이 매우 복잡하다. *명령어의 표를 참조하고 유형을 분석하여 길이를 구한다.
어셈블러 설계 - 패스 2
패스 2는 목적 프로그램을 만든다.
- 심볼의 값을 찾는다.
- 명령어를 만들고 object 파일에 추가한다.
- 상수, 심볼등의 데이터를 만든다.
자료구조
- 소스 프로그램 사본
- 명령어 테이블
- 심볼 테이블
- LC
- 목적 프로그램 출력
소스 토큰화
입력받은 어셈블리 소스를 필드 별로 나눠야 함
소스 라인 규칙 :
-
레이블 명령어 op1 op2 - 레이블 뒤에는 콜론(:)
- 빈칸, 쉼표, whitespace 에 대한 예외 처리
테이블
명령어 테이블은 크기가 정적임.
struct inst {
char inst_name[4];
char inst_code[4];
int number_of_opnd;
}
struct inst inst_table[8] = {
{"BEQ", "000", 2}, {"SUB", "001", 2}, ...
{"ASL", "111", 2}};
반면 심볼 테이블은 동적
struct symbol {
char symbol_name[9];
int value;
int lc;
} symbol_table[100];
struct symbol *ptr;
ptr = (symbol *)malloc(sizeof(struct symbol));