[시스템프로그래밍] Assembler: 어셈블리 언어로 작성된 프로그램을 기계어 코드로!

장다희·2025년 4월 9일

시스템프로그래밍

목록 보기
2/9

Assembler

어셈블리 언어로 작성된 프로그램을 기계어 코드(.o와 같은 object files)로 변환해주는 시스템 소프트웨어

  • 모든 어셈블러가 수행해야 하는 핵심 기능
    • 기호 형태의 연산 코드(Mnemonic operation codes)를 기계어로 변환
      → opcode table 이용해 변환 ( LDA00 )
    • 모든 symbolic labels에 정확한 기계 주소 할당
      → symbol table 을 만들어 label 추적
  • 어셈블러는 명령어 format과 addressing mode(주소 지정 방식)에 따라 동작이 달라진다. (Machine-dependent Assembler Features)

용어 정리

  • Assembly language? 기계가 이해하는 명령어의 기호적 표현 (사람이 읽기 쉬운 형태)
  • Object file? 기계어 명령어 + 데이터 + 메모리 배치에 필요한 정보가 결합된 파일
  • label? 명령어 또는 데이터가 위치한 메모리 주소에 붙인 이름
  • Opcode Table? 어셈블리어의 연산 코드와 실제 기계어 코드를 매핑한 표
  • Symbol Table? 프로그램에 사용된 레이블과 해당 메모리 주소를 연결한 표

Assembly Language Statements

functional statements 3가지

🔴 명령어 (Instructions)

어셈블러에 의해 1개 이상의 object code 바이트로 번역됨
이 코드는 실행 시간에 실제 실행됨
각 명령어는 하나의 연산(기능)에 대응됨

🔴 지시어 (Directives)

어셈블러에게 특정 작업을 수행하라고 지시함
object code에는 영향을 주지 않음
예: WORD 지시어는 1-word 정수를 생성하는 데이터 정의어이다.

🔴 매크로 (Macro)

여러 문장을 축약해서 나타낸 것
어셈블러는 매크로를 그에 해당하는 문장들로 확장한 다음,
이 확장된 문장들을 어셈블함

🔷 매크로 정의

READ  MACRO &BUFFER
      STA &BUFFER
      ...
      MEND

READ MACRO &BUFFER:

  • 매크로 READ 정의
  • &BUFFER : 매크로 인자(parameter)
    → 매크로를 호출할 때 인자로 전달한 값이 이 &BUFFER 자리에 들어감

STA &BUFFER:

  • 실제 매크로가 실행되면 수행될 명령어
  • A 레지스터의 값을 &BUFFER가 가리키는 메모리 주소에 저장

MEND: 매크로 정의 끝

🔷 매크로 사용

READ   INDEV
...
INDEV BYTE X'F1'

→ INDEV에 0xF1을 저장해 두고, 그 후 A 값으로 덮어씀

READ INDEV:

  • 매크로 호출, INDEV는 그 매크로에 전달되는 인자
    → 매크로가 확장되어 STA INDEV를 의미하게 됨
  • 레지스터 A의 값을 INDEV라는 주소에 저장

INDEV BYTE X'F1':

  • INDEV라는 주소에 1바이트 값 0xF1 저장
  • 단순히 INDEV라는 이름의 메모리 공간을 잡고 초기값으로 0xF1을 넣음

Assembly source program ➝ Object program

어셈블리 소스 프로그램을 오브젝트 프로그램으로 변환하는데 필요한 기능은 아래와 같다.

1️⃣ mnemonic operation codes (기호 명령어) ➝ machine language codes

  • STL14 (hex)

2️⃣ symbolic operands ➝ machine addresses

  • RETADR1033

3️⃣ 변환된 값을 이용해 주소 지정 방식(addressing mode)을 포함한 정해진 형식의 기계어 명령어 구성

4️⃣ 소스 프로그램 내에 지정된 데이터 상수(data constants) ➝ internal machine representations

  • EOF454F46 (ASCII로 E, O, F)

5️⃣ 오브젝트 프로그램과 어셈블리 리스트 파일 생성

그러나 1️⃣~5️⃣의 과정을 소스코드 한 줄씩 순차적으로 처리한다면, translating address 과정에서 문제가 발생할 수 있다. 바로 Forward reference (전방 참조) 때문이다.

⚠️ Forward reference

Forward reference란 프로그램의 앞부분에서 라벨을 사용하지만, 해당 라벨은 프로그래밍 뒷부분에 정의되는 상황이다.

예를 들어,

Line	LOC	  Source Statement	   Object Code
10	   1000	  FIRST STL RETADR	   141033
...
95	   1033	  RETADR RESW 1

위에서 RETADR는 Line 10에서 사용되었지만, Line 95에서 정의되어 아직 RETADR의 주소를 알 수 없다.

➡️ Forward reference 문제를 해결하기 위해 대부분의 어셈블러는 소스 프로그램을 두 번 통과시킨다!
→ 이러한 어셈블러를 2-pass Assembler라고 한다.

2-pass Assembler

🔴 Pass 1: Symbol 정의

  • 어셈블리 코드의 한 줄을 읽고 해당 명령문에 주소를 할당한다.
    → 바이트 단위로 주소를 증가시키고, LOCCTR(위치카운터)를 사용한다.

  • 모든 label에 할당된 주소 값을 저장한다.
    → 2단계에서 사용하기 위해 symbol table에 저장한다.

  • 일부 어셈블러 지시어 처리를 수행한다.
    → 상수 선언, 공간 예약 등
    → 예: BYTE, RESW 등의 크기에 따라 주소 할당에 영향을 주는 지시어 처리 포함

  • 알고리즘

    begin
      첫 번째 입력 줄을 읽는다
      if OPCODE가 'START'라면 then
        begin
          #[OPERAND]를 시작 주소(starting address)로 저장한다
          LOCCTR(location counter)를 시작 주소로 초기화한다
          해당 줄을 중간(intermediate) 파일에 기록한다
          다음 입력 줄을 읽는다
        end (if START)
      else
        LOCCTR을 0으로 초기화한다
        
         ▒▒▒
       
        마지막 줄을 중간(intermediate) 파일에 기록한다  
        (LOCTR - 시작 주소)를 프로그램 길이로 저장한다
    end {Pass 1}

    ▶ #OPERAND는 START 지시어 뒤에 나오는 주소 값 (예: START 1000)
    ▶ LOCTR은 현재 명령이 메모리에 배치될 주소를 추적하는 위치 카운터

    while OPCODE ≠ 'END' do
      begin
        if 이 줄이 주석이 아닌 경우 then
          begin
            만약 LABEL 필드에 심볼이 있다면
              begin
                SYMTAB에서 LABEL을 검색한다
                if 이미 존재한다면
                  → 에러 플래그 설정 (중복 심볼)
                else
                  → (LABEL, LOCTR) 쌍을 SYMTAB에 삽입
              end (if symbol)
    
            OPTAB에서 OPCODE를 검색한다
            if 찾았다면
              → LOCCTR에 명령어 길이(보통 3)를 더한다
            else if OPCODE = 'WORD' then
              → LOCCTR에 3 더하기
            else if OPCODE = 'RESW' then
              → LOCCTR에 3 * #[OPERAND] 더하기
            else if OPCODE = 'RESB' then
              → LOCCTR에 #[OPERAND] 더하기
            else if OPCODE = 'BYTE' then
              begin
                상수의 바이트 길이 계산
                LOCCTR에 해당 길이만큼 더하기
              end (BYTE)
            else
              → 에러 플래그 설정 (유효하지 않은 OPCODE)
          end (if not a comment)
      
        중간 파일에 현재 줄을 기록
        다음 입력 줄을 읽음
      end
    end (while not END)
    

➡️ 결과: 각 source statement와 그에 할당된 주소, 에러 표시 등을 포함한 중간 파일(intermediate file)을 생성한다.

🔴 Pass 2: Instruction 조립 및 object program 생성

  • 한 줄씩 코드를 읽는다.
    → Pass 1에서 생성된 intermediate file을 2단계의 입력으로 사용한다.

  • opcode을 번역한다.
    → OP Code Table 사용

  • label을 address로 변환한다.
    → Symbol Table 사용

  • 1단계에서 수행하지 않았던 assembler directive를 처리한다.

  • 알고리즘

    begin
      중간 파일에서 첫 번째 입력 라인을 읽는다
    
      if OPCODE = 'START' then
        begin
          리스트 파일에 라인을 기록한다 (write listing line)
          다음 입력 라인을 읽는다
        end {if START}
    
      객체 프로그램에 헤더 레코드를 작성한다 (write Header record)
      첫 번째 텍스트 레코드를 초기화한다 (initialize first Text record)
    
      ▒▒▒ [텍스트 레코드 생성 및 명령어 번역 등 핵심 처리 영역] ▒▒▒
    
      마지막 텍스트 레코드를 객체 프로그램에 기록한다
      객체 프로그램에 END 레코드를 작성한다
      마지막 리스트 라인을 작성한다
    end {Pass 2}

    begin
      if 이 줄이 주석 줄이 아니라면 then
        begin
          OPCODE가 OPTAB에 있는지 검색
          if 발견되면 then
            begin
              피연산자(OPERAND)에 심볼이 있다면 then
                begin
                  그 심볼이 SYMTAB에 있는지 검색
                  if 발견되면 then
                    피연산자의 주소로 해당 심볼의 값을 저장
                  else
                    begin
                      피연산자 주소로 0 저장
                      에러 플래그 설정 (정의되지 않은 심볼)
                    end
                end (if symbol)
              else
                피연산자 주소로 0 저장
    
              객체 코드 명령어를 조립 (assemble the object code instruction)
            end (if opcode found)
    
          else if OPCODE = 'BYTE' 또는 'WORD' 라면 then
            상수를 객체 코드로 변환
    
          if 객체 코드가 현재 텍스트 레코드에 들어갈 수 없다면 then
            begin
              현재 텍스트 레코드를 객체 프로그램에 기록
              새로운 텍스트 레코드 초기화
            end
    
          객체 코드를 텍스트 레코드에 추가
        end (주석이 아니라면)
      
      리스트 라인 기록
      다음 입력 라인 읽기
    end (while not END)
    

➡️ 결과: object program 생성

SIC 어셈블러의 두 가지 데이터 구조

🔹 Operation Code Table (OPTAB)

mnemonic(기호 형태의) op code와 그에 대응하는 machine language 값 저장
→ 보다 복잡한 어셈블러의 경우, 명령어 형식과 길이가 가변적인 경우 이러한 정보도 포함할 수 있다.

  • Pass 1: mnemonic code 검색, 유효성 검사

  • Pass 2: assembly code → machine language

  • 보통 Hash Table로 구성

    • Key: mnemonic code
    • 최소한의 탐색 → 빠른 검색
    • 한 번 생성되면 OPTAB은 변경 X

🔹Symbol Table (SYMTAB)

소스 프로그램의 각 label에 대해 name과 value (address) 저장

  • 오류 상태 같은 flag 정보
  • label이 가리키는 instruction 또는 data의 타입이나 길이 정보
  • Pass 1: 각 label이 등장하면 해당 label과 LOCCTR에서의 주소를 SYMTAB에 저장

  • Pass 2: 명령어의 operand로 등장한 symbol을 SYMTAB에서 검색해 해당 주소로 변환

  • 보통 Hash Table로 구성
    → 빠른 삽입과 검색

0개의 댓글