임베디드 면접 용어 사전
펌웨어 빌드

크로스 컴파일

개발 PC에서 다른 아키텍처용 바이너리를 만드는 빌드 방식.

개발하는 컴퓨터(호스트)와 실행할 기기(타깃)의 아키텍처가 다를 때 호스트에서 타깃용 바이너리를 만드는 것.

호스트: x86-64 리눅스/윈도우/맥

  • 타깃 — : ARM Cortex-M

x86 컴파일러로는 ARM 명령어를 만들 수 없다 → 크로스 컴파일러 필요

툴체인 이름 읽는 법

arm-none-eabi-gcc
 │    │     │    └── 도구 이름
 │    │     └─────── ABI (Embedded ABI)
 │    └───────────── OS (none = 베어메탈)
 └────────────────── 아키텍처

arm-linux-gnueabihf-gcc
      └── OS가 리눅스, hf = 하드웨어 부동소수점

nonelinux의 차이가 중요하다.

  • arm-none-eabi — : OS 없음. newlib. MCU 펌웨어용 arm-linux-gnueabihf : 리눅스 있음. glibc. 임베디드 리눅스 애플리케이션용 잘못 고르면 시스템 콜을 기대하는 libc가 링크되어 동작하지 않는다.

구성 요소

  • gcc — 컴파일러
  • as — 어셈블러
  • ld — 링커
  • objcopy — 포맷 변환 (elf → bin/hex)
  • objdump — 역어셈블, 섹션 정보
  • size — 섹션 크기
  • nm — 심볼 목록
  • gdb — 디버거
  • newlib — C 표준 라이브러리 (임베디드용)

필수 컴파일 옵션

arm-none-eabi-gcc \
  -mcpu=cortex-m4 \                      # 코어
  -mthumb \                              # Thumb 명령어 (Cortex-M 필수)
  -mfpu=fpv4-sp-d16 -mfloat-abi=hard \   # FPU
  -DSTM32F407xx \                        # 칩 정의
  -Os -g3 \
  -ffunction-sections -fdata-sections \
  -Wl,--gc-sections \
  -T STM32F407.ld \                      # 링커 스크립트
  -Wl,-Map=out.map \
  --specs=nano.specs \                   # 경량 libc
  main.c -o firmware.elf

-mfloat-abi 는 반드시 일치시켜야 한다.

  • soft — : FPU 없음. 소프트웨어 에뮬레이션
  • softfp — : FPU 사용하지만 함수 인자는 정수 레지스터로 (호환성)
  • hard — : FPU 레지스터로 인자 전달. 가장 빠름

라이브러리와 ABI가 다르면 링크 에러가 난다. error: uses VFP register arguments, output does not 가 그것이다.

반호스팅(semihosting) — 주의할 함정

--specs=rdimon.specs      # printf 가 디버거를 통해 PC 콘솔로 출력
--specs=nosys.specs       # 시스템 콜을 스텁으로 (아무것도 안 함)

반호스팅은 디버거가 연결되어 있어야 동작한다. 디버거 없이 실행하면 printf에서 멈춘다 — 브레이크포인트 명령을 실행하는데 응답할 디버거가 없기 때문이다.

양산 펌웨어에서 반드시 제거해야 하며, "디버거를 빼면 동작하지 않는다"의 대표 원인이다.

_write 재구현 — printf를 UART로

int _write(int fd, char *ptr, int len) {
    HAL_UART_Transmit(&huart2, (uint8_t *)ptr, len, HAL_MAX_DELAY);
    return len;
}

nosys.specs와 함께 쓰면 printf가 UART로 나간다. 임베디드에서 가장 흔한 로그 출력 방법이다.

빌드 시스템

  • Makefile — — 전통적. 세밀한 제어
  • CMake — — 크로스 플랫폼. 툴체인 파일로 크로스 컴파일 설정
  • PlatformIO — — 라이브러리 관리 포함
  • 벤더 IDE — — STM32CubeIDE, MCUXpresso (Eclipse 기반)
# CMake 툴체인 파일
set(CMAKE_SYSTEM_NAME Generic)          # ★ 중요
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER arm-none-eabi-gcc)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)   # ★ 링크 테스트 회피

CMAKE_TRY_COMPILE_TARGET_TYPE 을 설정하지 않으면 CMake가 컴파일러 검사를 위해 실행 파일을 만들려다 실패한다. 링커 스크립트 없이는 링크가 안 되기 때문이다. 자주 겪는 문제다.

결과물 변환

arm-none-eabi-objcopy -O binary firmware.elf firmware.bin
arm-none-eabi-objcopy -O ihex   firmware.elf firmware.hex
arm-none-eabi-size firmware.elf

재현 가능한 빌드

같은 소스가 항상 같은 바이너리를 만들어야

  • 배포된 펌웨어와 소스의 대응을 검증할 수 있다

  • 인증·감사에서 요구된다

  • 방해 요소: DATE, TIME 매크로, 절대 경로, 빌드 순서

  • -ffile-prefix-map, SOURCE_DATE_EPOCH 등으로 제거

도커 컨테이너로 툴체인 버전까지 고정하는 것이 현대적 관행이다. 컴파일러 버전이 다르면 바이너리가 달라지기 때문이다.

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 펌웨어 빌드·부팅 — 빌드 과정·메모리 섹션(.data/.bss)·링커·startup·OTA