[TIL]C의 malloc 은 어떻게 모든 플랫폼에서 동작하는가?
c의 malloc 을 직접 구현해 보는 malloc_tutorial.pdf 을 읽고있습니다.
리눅스의 syscall 을 써서 구현하더라구요. 그럼 윈도우에서는 어떻게 구현하지 이런 질문이 머리속에 떠올랐습니다.
GPT 와의 문답을 정리해 봤습니다.
오랜만에 대학시절에 배운것들도 생각나고 재밌었네요.
소프트웨어는 하드웨어를 제어한다. C는 고수준 언어이면서도 높은 하드웨어에 제어능력을 가진다.
atmega128 이라는 MCU(micro controller unit) 에서 돌아가는 프로그램을 C 로 만들때는 데이터시트를 읽고 특정 레지스터 에 바이트를 쓰거나 특정 핀에 출력을 제어하는 저수준 프로그램을 짰다. 예를들어 레지스터에 특정 값을 설정하는
DDRB |= (1 << PB0);같은 코드. c 파일에는 atmega128 를 사용하기 위한 라이브러리인avr/Io.h가 포함된다.
c 코드는 atmega128 를 타겟으로 컴파일 된다. (avr-gcc 를 사용한다.) 컴파일 결과는 atmega128 의 기계어이다. 이 결과물은 atmega128 과 연결된 메모리에 올라가고 운영체제 없이 식접 atmega128 를 제어한다. 이러한 OS 레이어를 거치지 않는 프로그래밍을 베어메탈 프로그래밍 이라고 한다.
그럼 아두이누는 뭘까 아두이누에도 atmega 계열의 MCU 가 올라간다. 하지만 아두이누는 하드웨어 제어를 위해서 한단계 추상화한 계층을 제공한다.
avr/Io.h를 사용할때는 레지스터를 제어하던 코드는 아두이누에서는pinMode(13, output)와같은 고수준 표현이 된다. 당연히 아두이누용으로 c 코드를 컴파일하면 기계어가 나온다.그럼 리눅스 운영체제 위에서 c 코드를 컴파일 하면 어떻게 되는걸까? 컴파일 결과물은 리눅스 전용이다. 컴파일 결과물은 리눅스커널을 통해서(OS레이어를 거쳐서) 하드웨어와 소통한다. 컴파일 결과물은 기계어다. 단지 리눅스위에서 실행될 뿐이다.
그럼 어셈블리어 는 뭘까? 어셈블리어는 기계어 보다 딱 한단계 높은 수준의 언어이다. 어셈블리어는 CPU 아키텍쳐에 종속적이다. 기계어로 프로그래밍을 하는 것 보다. 높은 수준의 어셈블리어를 사용하는게 사람에게는 더 편하다. 지금 우리는 JAVA와 같은 고수준 언어를 작성하고, 특정 문제에 대해서 DSL(domain-specific-langage) 을 사용해 프로그래밍 하기도 한다.
현대 컴파일러는 어셈블리어를 생성할 수도 있고, 바로 기계어를 생성 할 수도 있다. 지금도 어셈블리어 결과물이 필요할 때가 있을까? 있다. 디버깅이나 성능 최적화에 사용할 수 있다. 어셈블리어에서는 높은 레벨의 언어가 추상화 하는 프로그램의 런타임의 행동을 보다 쉽게 이해할 수 있다.
컴파일단계는 다음과 같이 단계를 나눌 수 있다.
[Front-end (언어 분석)] → [IR (중간 표현)] → [Back-end (기계어 생성)]이렇게 단계를 나누면, 언어가 추가될때는 FE 부분을 변경하고 CPU 아키텍쳐가 추가되면 BE 부분만 변경하면 된다.
중간단계를 가지는 것으로 없던 이식성이 생긴다.자바를 컴파일 하면 바이트코드가 생성된다. 바이트코드는 VM 위에서 동작하는 기계어 같은 것이다.
바이트 코드도 일종의 중간표현이다.이렇게 보니 JAVA의 bytecode, JVM 아이디어는 엄청나게 혁신적이라기 보다는, C 와 다른 설계철학으로 기존 아이디어를 확장 JVM의 구현으로 Write once, run anywhere 를 달성한 것 처럼 보인다.
요즘은 WebAssembly 라는 바이트코드 포맷이 있다. C로 작성해서 결과물이 WebAssembly 이 되도록 컴파일 하면, JVM 과 같은 런타임, 예를들면 node.js, V8, Wasmtime 위에서 실행할 수 있다.
다시 C로 돌아와서 C 의 컴파일 결과물이 플랫폼(OS)에 종속적 이라면 malloc 표준 라이브러리는 어떻게 같은 동작을 하는걸까? 실제로 표준 라이브러리의 malloc 을 열어보면 시그니쳐만 확인할 수 있다. 마치 JAVA의 interface 와 같은 것이다.
실제 구현은 아래처럼 시스템 마다 다른 파일에 위치해 있다.리눅스: glibc/malloc/malloc.c
맥: libmalloc
윈도우: msvcrt.dll
컴파일을 하면 이것들과 malloc 이 링킹 된다.