주소 바인딩

skycloud의 이미지

compile time에 정해지면 정해진 주소에 정해진 값이 있어야 하고
loading time에 정해지면 상대적인 주소를 프로그램을 실행할 때 마다 매번 계산해야 하고
excution time에 정해지면 그것과는 상관 없이 MMU를 통해서 주소를 알게되는데
excution time에 결정되어 실행되는 경우 실제 주소가 매번 바뀌며 언제 바뀌는지 모른다고 하더라구요 그런데 왜 그런가요?
프로그램이 메모리에 적재되고 프로세스의 상태가 run이라고 하더라도변수의 주소가 run 상태의 시간 안에도 바뀔 수 있다는 뜻인데 그게 어떻게 가능하죠? 그리고 실행중인 프로세스의 위치를 바꿀 필요가 있나요? 실행 중이면 고정시켜서 사용하면 될 것같은데 말이죠

swish95의 이미지

실행될때마다 메모리 영역이 달라질텐데 항상 같은 주소로 매핑된다고 생각하는건 이상하지 않나요?

------------------------------------------------------------
ProgrammingHolic

awdxawdx101의 이미지

제가 아는 한에서 답변을 드리자면...

실행중에 주소가 바뀔 수 있는건 가상 메모리만 봐도 항상 같은 프레임에 같은 페이지가 로드된다는 보장이 없기때문에 주소가 바뀔 수 있다는 것을 알게될겁니다.

라스코니의 이미지

물리적 주소를 접근해야 하는 경우 (커널 디바이스 드라이버와 같이) compile time시에 결정해도 됩니다. 대부분의 간단한 임베디드 소프트웨어는 아마 #define 등으로 미리 선언되는 방식을 쓸 겁니다. 하지만 조금만 시스템이 복잡해져도 이런 방식이 통하지 않기 때문에 getBaseAddress() 등의 함수를 써서 하드웨어 접근 시작 번지는 runtime에 가져오는 경우가 많습니다.

가상 주소를 접근하는 경우 (process 또는 thread 내에서) 그야말로 가상이므로 그 주소가 반드시 할당된다는 보장은 없습니다. 간단한 소프트웨어의 경우 보통 똑같은 순서로 모듈이 로드되기 때문에 똑같은 주소값을 갖기도 합니다만 별 의미가 없습니다.

Stephen Kyoungwon Kim@Google의 이미지

본문 전제가 이상합니다. MMU는 virtual to physical memory mapping입니다. 링커나 로더는 virtual address만 보거나 physical address를 봅니다. 전자의 경우, virtual address는 응용 프로그램에서 보면 추상된 physical address고 굳이 원래 physical address가 뭐였는지 알 필요 없이 대부분의 경우에 사용 가능해야 합니다. 따라서 언제 symbol resolution이 일어나는지와는 관계가 커보이지 않습니다.

컴파일 타임 바인딩만으로 충분하지 않은 이유와 쉐어드 라이브러리가 필요한 이유가 상당히 겹칠 겁니다. share library를 안 쓴다면, code는 언제나 특정 virtual address에 배치하고, global 영역, heap, stack은 어디서부터 어디까지 배치하고.. 이런 식으로 정하는 게 불가능하진 않을 겁니다.

shared library가 들어가게 되면, 이제 그 프로세스의 address space에 커널 + 실행파일 (및 그 컨텍스트) 뿐만 아니라 임의의 개수의 shared library까지 포함하게 됩니다. shared library마다 각각 virtual address를 고정시켜 주는 건 이제는 매우 어렵겠죠. 그래서 shared library는 process마다 virtual address space 상의 다른 위치를 차지하게 됩니다. 이런 경우는 기본적으로 혹은 나이브하게는 load time에 address를 정해줄 수 있습니다.

세 가지 중에 소위 execution time에 address binding을 하는 경우는.. 여러 가지가 있겠습니다만, shared library를 어떻게 efficient하게 loading하느냐의 관련된 문제들이 많습니다. 나이브한 접근 방식은 share library를 loading time에 load 해놓고 address를 계산해 주는 거겠죠.

하지만 실제로는 그렇게 안 하는데, lazy loading이라고 부릅니다. loading time을 짧게 하고 처음 호출이 되면, 그때 로딩을 해놓는 거죠.
https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter3-7.html

그밖에 웹 서버가 아주 오래 전에는 cgi 요청 들어오면 exec, fork, redirect 등을 해서 서비스를 해줬을 텐데, process를 하나 만드는 건 효과적이지 않죠. 그걸 런타임 라이브러리로 만든다고 가정해 봅시다. 원래는 1000가지의 별도의 프로그램이 있어서 exec, fork, redirection을 해가며 썼다고 하고요. 이젠 대충 1000개의 .so가 필요합니다. 이걸 언제 load할 거냐가 문제겠죠. 웹 서버의 load time에 하면 1000개를 전부 로드해야 됩니다. 하지만 실제로는, 이를테면, 1000개 중에 4 ~ 5개만 엄청나게 자주 요청되고 나머지는 드물게 되거나 할 거고요. 그러면 1000개를 로드 타임에 다 로드하는 건 효율적이지 않습니다. 더 나은 방식은 아마 처음 요청을 받으면 그 라이브러리만 로드해서 캐슁을 하고, 안 쓰인지 오래 되면 버리는 거겠죠. 그러러면 런타임에 load해서 address binding이 가능해야 합니다.

그리고.. 그냥 한 가지 더 생각할 만한 건, JAVA VM 같이, 평소에는 interpreter인데 runtime에 모니터 하다가 hot spot을 발견하면, just-in-time 컴파일을 하고 이제는 interpreting 대신 그 컴파일된 코드를 사용하는 경우일 겁니다. 그때 binary translation이 뒤늦게 런타임에 된 코드는 로딩이 될 때 주소도 고정되기 어렵겠죠. 이런 feature를 시스템이 허용한다면 도대체 어떤 프로그램이 언제 몇 개의 그런 류의 코드를 생성할지 예측할 수 없으니까요.

Stephen Kyoungwon Kim@Google의 이미지

주소가 across processes로 고정되어 있으면 좋죠. 안 되는 상황이 있으니까 문제인 거고요.

Linux + x86은 shared library를 무한 개 만들 수 있습니다. 오늘 저도 hello world X 찍는 libhelloX.so를 X만 바꿔 가며 만들 수 있습니다. 링커나 로더는 이 libhelloX.so나 모든 미래의 쉐어드 라이브러리가 모든 프로세스에서 사용될 수도 있다고 가정해야 합니다. 이걸 주어진 라이브러리의 심볼들을, 모든 프로세스의 주소 공간 상에 동일한 주소에 배치하는 걸로는 해결하기가 어렵죠. 링커 관점에서 보면, shared library로 된 무한 집합의 임의의 부분 집합이 주어질 때 compile time에 address를 정해줄 수 있어야 하는데, 어렵죠.

load time에는 쉐어드 라이브러리 로드는 가능은 합니다. 하지만 효율적이지 않은 경우도 있고, shared library 외의 용례에서는 안 되는 경우도 있죠.

예컨대 비록 1000개의 shared library와 링크가 되어 빌드는 되었지만, 실제로 그 중에 너댓개만 자주 쓰고 나머진 드물게 쓴다고 해보죠. 로드 타임에 하려면 전부 다 링크를 해야 하는데 낭비일 겁니다.

어떤 경우에는 응용 프로그램이 사용하는 코드의 일부가 수행 중에 빌드되기도 합니다. 그런 경우엔 로드 타임에 아예 로드를 할 수가 없죠. 제 생각엔 Just-in-Time compiler가 만드는 것들은 대개 이런 식일 듯 합니다. 혹은 qemu처럼 runtime binary translation이 필요한 경우도 마찬가지입니다. 런타임에 빌드는 하지만, 주어진 10개 중에 일부만 그렇게 한다면 address 자체는 compile/load time에 미리 할당해 놓는 것도 가능합니다. 하지만 qemu나 JIT의 경우 임의의 코드를 translate하기 때문에 런타임에 로드할 가능성이 있는 코드의 개수는 무한합니다.

MMU 얘기는 누가 했는지 모르겠는데, 링커/로더와는 상관없습니다. MMU는 가상 메모리 주소를 물리 메모리 주소로 번역합니다. 커널과 달리 링커나 로더는 대부분, 가상 메모리가 있는 시스템이라면, 가상 메모리만 알면 됩니다. 그런 시스템에서 실행 파일이나 컴파일 모듈에 적힌 주소는 가상 메모리 주소입니다. 8051처럼 MMU도 없고 OS도 없는 시스템에 펌웨어를 올리는 거면, 링커가 인지하고 사용하는 모든 주소는 물리 주소가 됩니다.

링커나 로더가 아는 건 물리/가상 주소가 아니라 그냥 주소입니다. 그게 가상 주소인 시스템과 물리 주소인 시스템이 있는데 링커/로더는 어느 쪽인지 보통 관심이 없습니다.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.