MIPS 컴퓨터 구조에 어셈블리어를 확인해봤을 때, 이는 엄연히 프로그래머 수준의 코드이다.
이러한 이유로 가독성을 높히기 위한 instruction들을 Pseudo-instruction이라 부른다.
이 명령어들은 사실 존재하지 않으며 기계어로 번역되었을 때 다른 명령어의 집합으로 표현된다.
예시를 확인해보자.
move $t0, $t1 → add $t0, $zero, $t1
blt $t0, $t1, L → slt $at, $t0, $t1
bne $at, $zero, L
여기서 $at 레지스터는 어셈블러가 어셈블리 과정에서 사용하는 레지스터로 temporal한 상수값을 저장한다.
blt는 존재하지 않으므로 slt(1 or 0)를 이용하여 도출한 값을 0과 비교하여 같지 않으면 L로 점프하는 모습을 확인할 수 있다.
어셈블러가 어셈블리어를 기계어로 번역할 때 이를 하나의 모듈로 표현한다.
이 모듈의 형식은 아래와 같다.
- Header: segement의 위치(크기) 등 정보
- Text segment: 기계어가 저장된다.
- Static data segment: 전역변수, 정적변수가 저장된다.
- Relocation info: 각 파일들을 하나의 실행가능한 파일로 만들 때, 이를 위한 정보이다.
- Symbol table: 전역변수와 referecne의 정보.
예를 들어, 다양한 파일의 전역변수의 사용하는 부분과 선언부가 다를텐데, 이들을 엮어주기 위한 정보들이다.- Debug info: 디버그를 위한 부분이다. 컴파일 과정 이전의 소스코드와 관련지은 정보가 포함된다.
링킹의 과정을 간단하게 알아보자.
- segment들을 하나로 묶는다.
- label들을 resolve한다.(함수들에 붙여놓은 label을 실제 주소로 바꿔준다. 원래는 label로 표현되어 있다.)
- sympol table들, 즉 사용됐지만 정의부가 어디있는지 몰랐던 선언부와 엮어준다.(실제 메모리 주소)
이제 링킹 단계를 지나 하나의 실행가능한 파일이 만들어졌다. 이를 메모리에 로드하는 과정을 알아보자.
- header에 있는 segment의 크기를 통해 메모리에 할당할 segment의 크기를 정한다.
- 메모리 공간을 확인한다.
- text와 data를 확보한 메모리 공간에 로드한다.
- stack을 잡아준다.
- 레지스터를 초기화한다.($sp, $fp, $gp)
- main 함수를 실행한다.(매개변수로 전달해야하기 때문에 레지스터에 저장한다.)
동적 링킹이란, 만약 특정 모듈을 사용한다 했을 때, 이에 대한 코드를 실행프로그램의 정적 링킹과정에 포함시키지 않고, 실행될 때 동적으로 메모리에 올려 링킹하는 것을 의미한다.
(윈도우는 dll 확장자 파일을 사용한다.)
이것도 유지보수에 뛰어나다. 특정 함수들을 포함하는 모듈을 수정했을 때, 전체 프로그램을 수정하거나 다시 컴파일할 필요 없이 동적링킹으로 해결할 수 있다.
동적 링킹을 사용하면 많은 프로그램이 사용하는 함수 모듈이 독립적으로 디스크에 존재하기 때문에 공간을 아낄 수 있다. 하지만 프로그램들이 함수 모듈 중 하나의 함수를 실행할 때 메모리에 동적 링킹 파일이 올라간다. 그럼 많은 프로그램들이 함수 모듈을 전부 메모리에 올려 공간 낭비가 발생한다.
이를 해결할 방법이 Lazy linking이다.
각각의 프로그램의 메모리 공간에 함수 모듈을 로드하는 것이 아니라, 메모리 다른 곳에 하나의 모듈을 올려놓고 이를 가리키는 동적 링킹 방법이다.
실제로 함수를 호출했을 때 메모리 어디에 있는 지 모른다. Indirection table에서 호출한 함수를 찾는데, 만약 dummy(한 번도 호출이 안됨) value가 있다면 Stub이 함수의 ID정보를 알려준다. 이를 linker/loader code가 ID 정보를 통해 실제의 함수 주소를 DLL 파일에서 찾는다. 이를 indirection table에 저장하면 두 번째 호출부터 바로바로 호출할 수 있다.
Java compiler: source codes to bytecodes
JVM's interpreter: bytecodes to native machine codes
JIT: directly bytecodes to native machine codes: 이미 interpreter가 해석했던 inst를 해석 후 저장(함수와 같이 자주 일어날 경우), 해석하지 않고 바로 실행.