컴퓨터를 만듭시다. 어때요~ 참 쉽죠? (23)

나빌레라의 이미지

#23. 중간계에는 엘프가 산다.

프로그램을 만들 때 소소 코드의 파일을 여러개로 만드는데는 몇 가지 이유가 있다. 일단 규모가 어느 정도 이상되는 프로그램을 하나의 소스 코드 파일로 만들게 되면 그 복잡도나 분량이 갈수록 커진다. 나중에는 코드를 작성한 사람조차 자신의 소스 코드를 관리할 수 없는 지경에 이르게 된다. 그래서 논리적인 단위 혹은 기능적인 단위로 소스 코드를 분리하고 각각 분리된 소스 코드를 몇 개의 파일로 나눠서 만들면 복잡도가 어느 정도 내려간다. 또 무시못할 절대적 이유가 하나 더 있다. 바로 라이브러리의 활용. 자주 쓰는 함수같은 것들을 파일에 넣어두고 여러 프로그램에서 해당 파일에 있는 함수를 같이 사용하는 것이다.

라이브러리를 소스 코드 형태로 가져와서 내가 만들고자 하는 프로그램과 합친 다음 컴파일하여 기계어로 된 바이너리 파일을 만들 수 있다. 하지만 만약에 라이브러리가 굉장히 크다면? 나는 그 중에 두 세개 정도의 함수만 사용하는 상황이라면? 라이브러리의 소스 코드에서 내가 필요로 하는 함수만 떼내서 내가 만드는 프로그램에 붙여 넣을 수도 있겠지만 여러가지 전역 변수나 심볼등의 문제로 잘 되지 않는 경우가 더 많다. 그렇다고 내가 만든 프로그램의 소스 코드는 백 몇줄인데 수 십만 줄짜리 라이브러리를 컴파일하느라 몇 시간씩 걸리는건 용납할 수 없는 일이다.

어떻게 해결하면 좋을까? 간단하게 라이브러리를 미리 컴파일해 놓으면 된다. 하지만 라이브러리를 기계어로 완전히 컴파일 해 놓으면 내가 만든 소스 코드와 붙일 때 주소 영역 등이 제대로 들어 맞지 않는다. 그래서 일종의 중간 파일 역할을 하는 오브젝트 파일이라는 것을 만들고 opcode는 모두 기계어로 다 바꿔 놓은 다음 주요 심볼만 특정 부분에 재 배치 가능하도록 심볼 주소 및 참조 정보를 넣어 놓는다.

내가 만든 소스 코드 역시 오브젝트 파일로 만들고 그 파일에도 심볼 정보가 특정 영역에 있다. 그리고 컴파일러 말고 다른 프로그램으로 여러 오브젝트 파일의 심볼 정보를 취합해서 정리를 한 다음 하나의 기계어 바이너리 파일을 만들어 준다. 이 프로그램이 링커(Linker)다.

여러 오브젝트 파일들을 링커 고유의 순서에 맞춰서 배치하고 오브젝트 파일들에 등록된 여러 심볼들을 적절히 위치시키는 작업을 재배치라고 한다. 그래서 오브젝트 파일을 재배치 가능 파일 형식이라고 부르기도 한다. 또한 라이브러리를 오브젝트 파일 형태로 내가 만든 오브젝트 파일과 완전히 하나로 합쳐서 바이너리를 만드는 방법외에도 메모리 상에 떠 있는 라이브러리의 특정 영역을 필요한 순간에 재배치 해서 동작시키는 방법도 있다. 전자를 정적 링킹이라고 하고 후자를 동적 링킹이라고 한다. 동적 링킹은 정적 링킹에 비해 바이너리 파일(실행 파일)의 크기도 적고 컴파일도 빠른 장점이 있지만 링커의 구현이 어렵고 로더라는 또 다른 프로그램의 도움을 받아야 한다. 정적 링킹은 링커의 동작이 간단하고 때에 따라서는 로더가 필요 없기도 하다.

보통 플랫폼(cpu)별로 혹은 컴파일러, 운영체제에 따라서 오브젝트 파일의 형태가 다르다. 우리의 이야기에서는 운영체제는 아직 등장하지 않았다. cpu와 컴파일러는 지금 이야기를 하면서 조금씩 만들어가고 있다. 오브젝트 파일 형식으로 꼭 정해진 규칙같은 것은 없다. 몇가지 유명한 오브젝트 파일 형식이 있기는 하지만 유명한 만큼 범용적이고 범용적인 만큼 복잡하다. 그것을 가지고 와서 설명하는 것은 이 이야기와 맞지 않는다. 기회가 된다면 다른 이야기를 통해서 다뤄 볼 생각이다. 이 이야기에서는 내가 오브젝트 파일 형식을 하나 만들것이다. 그리고 그 오브젝트 파일을 링킹해서 최종적으로 기계어 바이너리 파일을 만들어주는 링커를 만드는 방법도 간단하게 이야기 할 것이다.

오브젝트 파일 형식을 설계할 때 반드시 고려해야 할 사항은 심볼 정보의 유지다. EXTERN으로 선언된 외부 참조 심볼은 그 심볼의 본체가 분명히 다른 파일에 있다는 뜻이기 때문에 심볼 정보를 제대로 관리하지 않을 경우 다른 파일에서 EXTERN 심볼이 값을 찾지 못해 프로그램 전체가 제대로 링킹되지 않는 경우가 생긴다.

컴파일러의 구현에 따라서 외부로 공개하는 심볼에는 export 등의 선언을 달고 extern 심볼은 다른 파일의 심볼 테이블에서 export된 심볼만 찾도록 링커를 구성하는 방법도 있다. 이 방법은 문법을 조금 복잡하게 하는 대신에 링커를 간단하게 구현할 수 있고 또한 오브젝트 파일의 크기도 줄일 수 있다. 왜냐면 오브젝트 파일에 포함시키는 심볼 정보는 export 심볼만 포함시키면 되기 때문이다. 하지만 지난 이야기에서 어셈블리어 문법을 정의할 때 나는 export 문법을 정하지 않았다. 오로지 EXTERN만 제일 마지막에 추가했을 뿐이다. 그러므로 EXTERN으로 선언된 심볼은 다른 오브젝트 파일의 심볼 테이블에 있는 모든 심볼에서 본체를 찾아야 한다. 그래서 내가 설계하는 오브젝트 파일에는 해당 어셈블리어 소스 파일의 모든 심볼 정보가 다 들어가 있어야 한다.

위 그림은 간단히 생각해 본 오브젝트 파일 형식이다. 내 닉넴임을 따서 나빌 오브젝트 파일 형식(Navil Object-file Format: NOF)라고 지어봤다. 더불어 지난 이야기에서 정의한 어셈블리어 문법은 나빌어셈이라고 이름 지었고, 그 전에 만든 opcode 체계는 나빌 아키텍처, cpu는 나빌 프로세서라고 지었다. 내가 만든것이기 때문에 내 아이디로 이름 붙여도 전혀 문제될게 없다. 나와 관계있는 그 무엇의 이름을 짓는 일은 재미있는 일이다.

헤더는 링커가 심볼 테이블의 데이터를 읽기위해 파일의 어느 위치에 어떤 심볼 테이블 정보가 있는지를 표시하기 위해 필요하다. 그리고 링커에 의해서 심볼 링킹 작업이 다 끝나고 나면 역시 헤더를 보고 기계어 코드의 시작 부분부터 읽어서 그것들을 모두 합쳐 최종 기계어 바이너리를 만들게 된다. 헤더는 중요하다.

내부 심볼 참조 테이블은 EXTERN으로 선언된 심볼을 제외한 모든 심볼에 대한 심볼 테이블 정보가 기록된다. 어셈블러가 어셈블리어를 컴파일 할 때 메모리상에 만드는 심볼 테이블을 그대로 파일에 기록한 것이라고 생각하면 된다. 여기에 기록된 심볼은 다른 오브젝트 파일의 EXTERN이 참조하고 있는 심볼일 가능성을 가지고 있기 때문에 반드시 필요하다.

외부 심볼 참조 테이블은 EXTERN으로 선언된 심볼이 기록된다. 여기에 기록된 심볼은 다른 파일의 내부 심볼 참조 테이블에서 주소 혹은 값을 읽어와서 해당 심볼을 참조하고 있는 opcode의 인자 영역에 값을 덮어 써 준다.

기계어 코드 부분은 지난 이야기에서 말했던 코드와 데이터 영역을 합친 것이다. 링커에 의해 링킹되는 각 오브젝트 파일의 기계어 코드 부분의 심볼 참조 부분이 심볼 테이블에 의해서 모두 완성된 후에 하나로 합쳐지면 그것이 완성된 기계어 바이너리 파일이 된다. PC라면 실행파일이 된다고 생각해도 좋다.

기계어 코드 부분이 합쳐질 때 링커에 의해 오브젝트 파일이 배열되는 순서가 정해진다. 이 순서에 따라서 기계어 코드 부분에서 참조하는 주소의 절대 값이 바뀐다. 이렇게 바뀐 주소의 절대 값을 정해주는 작업을 재배치 작업이라고 한다. 주소의 절대 값이 바뀌어도 해당 주소에 있는 심볼을 참조하는 코드는 그 유효성을 유지시켜야 한다. 이 역할 역시 링커가 해준다.

벌써 꽤 오래전에 이야기했던 주소 지정 방식 중에서 PC Relative, Reg-PC Relative 주소 지정 방식을 제외한 다른 주소 지정 방식은 모두 절대 값으로 주소를 지정한다. 그렇기 때문에 주소 재배치 작업에 의해서 심볼의 주소가 바뀐다면 다른 주소 지정 방식을 사용해서 주소를 지정한 opcode의 주소 영역의 값도 같이 바뀌어야 한다. 하지만 Relative 주소 지정 방식을 사용하면 주소의 절대 값으로 지정되는 것이 아니라 현재 opcode의 메모리 상 위치(PC)를 기준으로 아래 위로 몇 바이트 만큼 떨어진 곳에 위치한다라는 정보를 주는 것이기 때문에 재배치가 되더라도 그 상대적인 위치는 변하지 않는다. 그래서 Relative 주소 지정 방식을 사용한 opcode는 주소 지정 영역을 수정해 줄 필요가 없다.

주소 재배치는 이렇게 링커에 의해서 링킹 과정에서 수행되기도 하고 로더에 의해서 실행 과정에서 수행되기도 한다. 나는 이 이야기에서 로더라는 것을 등장시키지 않았다. 간단히 이야기하자면 로더는 프로그램을 실행시켜주는 프로그램이다. 파일 형태로 존재하는 프로그램을 읽어서 메모리에 올려주고 cpu가 해당 메모리 위치에서 opcode를 읽어서 동작을 하게 해주는 프로그램을 말한다. 일반 PC에는 로더가 존재한다.

내가 진행하는 이 이야기에서는 로더가 필요없다. 왜냐하면 내가 만든 cpu는 전원이 들어오면 무조건 메모리의 0x0000 번지에서부터 opcode 읽는 것을 시도하기 때문이다. 그래서 링커에의해 만들어진 기계어 바이너리 파일을 그대로 메모리의 0x0000 번지에 써 놓은 다음에 cpu에 전원을 넣으면 cpu는 알아서 opcode를 읽어 우리가 프로그래밍 한 대로 잘 동작한다.

만약에 cpu에 프로그램을 읽는 메모리 번지를 설정할 수 있게 한다면 링커는 재배치 작업을 할 때 시작 위치에 대한 정보를 가지고 주소를 지정해야 한다. 시작 위치가 0x0000이 아니기 때문에 모든 참조 위치에 시작 위치 만큼을 더해 주는 작업이 필요하다.

지난번 어셈블러를 이야기할 때와 마찬가지로 정말 제대로 수박 겉핥기를 했다. 링커에 대한 이야기는 내가 여기에 풀어놓은 것은 정말 1% 정도밖에 되지 않는다. 실제로 링커는 굉장히 복잡한 프로그램이며 중요한 프로그램이다. 그리고 그만큼 역할도 많고 하는 일도 많다. 하지만 그 모든 것을 다 다루는 것은 이 이야기에 맞지 않고 그 모든 것을 다 다루면 아주 두꺼운 책 한 권 분량이 나오기 때문에 다 다루는 것은 작정하고 책을 쓰지 않는한 섣불리 도전할 꺼리가 되지 않는다.

간단하긴 하지만 오브젝트 파일과 링커가 어떤식으로 연관되어 있고 그 둘이 무슨 일을 하는 것인지는 모두 이야기했다. 그리고 내 이야기는 점점 끝을 향해 달려가고 있다. 계속 읽어주고 계시는 여러분께 정말 감사의 마음을 전한다.

File attachments: 

댓글

neogeo의 이미지

냐아빌~

Neogeo - Future is Now.

Neogeo - Future is Now.

chunsj의 이미지

이제 책으로 나오길 기다리는 1인... ^^

나빌레라의 이미지

괜춘한 출판사 소개시켜 주길 바리는 1인...^^;
(아무데서도 출판을 안해준다능...)
----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라

----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라

lateau의 이미지

대학 출판사 쪽은 알아보셨나요. 제가 있던 대학만 해도 학술양성이라는 목적으로 괜찮은 집필인을 모집해서 책을 제작해주곤 했습니다.
상업 출판 쪽이 무리라면 대학 출판도 한 번 생각해볼 수 있을 듯 싶습니다. 대신 영업 쪽은 문외한이 많아서(라기 보다 관심이 없을지도) 판매 부수는 거의 포기해야하지 싶습니다.

또 하나의 방법은 돈은 많이 들지만 자가 출판... 도 있긴 합니다.
제 와이프가 그 쪽 일을 하는데 많이 비싸더군요. 이거 속된 말로 돈xx라고 하더군요.

--
I think to myself...what a emerging world.

나빌레라의 이미지

자비출판은 돈XX이 맞기 때문에 생각 안하고 있어요..^^

대학 출판사쪽은 연줄도 없고 아는 사람들도 없어서 알아보진 못했습니다.
(어차피 판매 부수 따위는 신경쓰지 않아요. 그냥 제 이름으로 ISBN 등록되는 거에 만족하는 것이지요.)

답글 감사합니다.^^
----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라

----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라

neogeo의 이미지

ebook 에 의한 출판은 아직 요원한가요? 꼭 물리적인 책이 아니더라도 괜찮을거 같은데...

Neogeo - Future is Now.

Neogeo - Future is Now.

나빌레라의 이미지

뭐 E-book도 출판해 주려는 출판사가 있어야 가능하죠..-_-;;;

ebook이라도 출판해주고 isbn 등록해준다면 감사하겠지만,

몇몇 출판사에 email을 보내 봤는데 다들 묵묵부답...

출판사 입장에서는 별로 매력적이지 않은 내용인가봐요..ㅎ

----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라

----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라

gogoonee의 이미지

e-book 도 모바일 앱처럼 오픈 마켓이 되면 좋을것 같은데요. 아님 개인 웹페이지에 PDF 파일 올려놓고 5000원 정도면 어떠실지요.
무료 배포의 봉사정신 보다는 5000원 정도의 저렴한 가격과 함께 여러 집필가들의 희망이 되어 주시면 좋겠네요. ^^

gogoonee의 이미지

글 타래에 잘못 연결되어 내용 지웁니다.^^

kimback100의 이미지

완전 생초보

복고또봐도 재미있고 조리있는 잘쓴글같ㄱ습니다. 추판하신다니 잘되었ㄷ으면 좋겠네여.....

홧팅하시고 앞으로도 더 좋은 글연구하시고 공부하셔서 올려주시기바랍니다.

감사합니다......

완전 생초보

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.