어셈블리의 밤 (2021)

Assembly Nights (2021)

ratfactor.com ▲ 71 댓글 23 andsoitis

요약

아이들을 재운 뒤 침대에서 낡은 넷북으로 x86 어셈블리를 익힌 개발자의 기록입니다.

개발자 데이브 가우어가 2021년에 쓴 글입니다. Zig 언어에 빠졌다가 시스템 프로그래밍과 컴퓨터 구조로 관심이 넓어졌습니다. 그 끝에 몇 년째 미뤄 둔 어셈블리 공부를 밤마다 시작했습니다.

왜 중요한가

  • 오래된 작은 기기와 잠들기 전 짧은 시간만으로도 미뤄 둔 공부를 꾸준히 이어 갈 수 있음을 보여 줍니다.
  • 결과물 완성보다 배우는 과정을 목표로 삼으면 프로젝트가 흐지부지되지 않는다는 경험을 전합니다.

핵심 내용

  • 소설책 대신 14년 된 Asus eeePC 701 넷북을 켜고 어셈블리를 짜는 것이 밤 일과가 됐습니다.
  • JonesForth(GNU 어셈블러 문법으로 쓴 Forth 언어 구현)를 NASM 문법으로 옮기는 작업을 했습니다.
  • 가장 어려운 일은 매크로(코드를 찍어 내는 틀) 변환이었고, 이해하는 데 몇 주 걸린 매크로도 있었습니다.
  • 서두르다 번역을 멈췄고, 명령어 하나하나를 GDB로 확인하며 작업 기록을 남기기로 했습니다.
  • 대부분의 프로젝트가 흐지부지됐지만 손대기만 하면 반드시 진척되는 프로젝트도 있다고 했습니다.

HN 반응

  • GDB로 어셈블리를 디버깅하는 선택을 의아해하는 댓글에, 인텔 문법으로 설정만 바꾸면 훌륭한 도구라는 반론이 이어졌습니다.
  • 손대기만 하면 성공하는 프로젝트라는 대목에 공감하는 댓글과, 자기 전 공부는 오히려 잠을 망친다는 경험담이 함께 나왔습니다.

댓글

19개 표시 · 전체 23개
  1. nickledave HN

    참고로 같은 저자가 Forth에 대해 쓴 글입니다: https://news.ycombinator.com/item?id=45639250

    그리고 최종 구현물입니다: https://ratfactor.com/repos/nasmjf/

    글 끝에서 저자가 언급한 『Programming from the Ground Up』 책은 여기서 볼 수 있습니다: https://programminggroundup.blogspot.com/2007/01/programming-from-ground-up.html https://download.savannah.gnu.org/releases/pgubook/

    지금은 접속이 안 되는 것 같은 asmtutor의 소스는 여기 있습니다: https://github.com/DGivney/assemblytutorials

    저는 이 토끼굴에 관심이 아주 많습니다. uxn의 탄생 배경도 비슷하니 한번 보세요: https://100r.co/site/weathering_software_winter.html

  2. WalterGR HN

    깨진 링크인 "Why no one should use the AT&T syntax ever, for any reason, under any circumstances"의 archive.org 미러입니다: https://web.archive.org/web/20251128060318/https://outerproduct.net/2021-02-13_att-asm.html

  3. 1vuio0pswjnm7 HN

    "역사적인" UNIX에 관심이 있다면 ATT 어셈블리를 읽고 (또 고칠) 줄 알아야 합니다.

    저자는 Intel 문법이 어디서나 쓰인다고 주장합니다. 맞는 말입니다. 하지만 "역사적인" UNIX 역시 어디에나 있습니다.

    어셈블리 문법을 두고 길게 늘어놓는 불평은 낡고 지겨운 클리셰입니다. 입문자에게는 재미있을지 몰라도, 오늘날 그런 불평으로 얻는 것은 글쓴이의 정신 상태(그래서 판단력까지)가 의심받는 것뿐입니다.

    "역사적인" UNIX 소스 트리에 들어 있는 ATT 문법 어셈블러 코드를 누가 Intel 문법으로 옮겨 주지는 않을 겁니다.

    Intel 문법을 쓰는 것은 얼마든지 좋습니다.^1

    그렇지만 "역사적인" UNIX가 관심사라면, 이런저런 단점이 있다고들 하더라도 ATT 문법을 읽고 고치는 데 익숙해 두면 계속 쓸모가 있을 겁니다.

    1. 저자 본인이 단 각주입니다:

    "GCC가 인라인 어셈블리에 Intel 문법을 쓰게 하려면 -masm=intel을 주면 됩니다. Clang에서는 안 되니 Clang 쪽에 따지세요. (아니면 인라인 어셈블리를 아예 쓰지 마세요. 어차피 좋은 생각인 경우가 드뭅니다.) objdump에는 -Mintel을 넘기고, gdb는 ~/.gdbinit에 set disassembly-flavor intel을 넣으면 됩니다."

    HN 독자 중에 이런 것을 좋아할 분도 있을 것 같습니다:

    https://raw.githubusercontent.com/pirate/assembly-repl/main/src/asmrepl.c

    https://github.com/pirate/assembly-repl

    (clang이 필요합니다)

  4. nickledave HN

    저도 이 링크를 올리려고 들어왔어요. 고마워요.

  5. RetroTechie HN

    "하지만 제가 깨달은 건, 그냥 매달리기만 해도 성공이 보장되는 프로젝트가 실제로 있다는 것입니다."

    어떤 활동에서든 이런 걸 찾아보세요. "관심을 쏟을수록 [X]가 더 아름다워 보인다"는 말과 비슷합니다. 노력을 더 들이면 그만큼 더 얻습니다.

    처음에는 재미있거나 쓸모 있어 보여도 결국 아무것도 남기지 않는 쓸데없는 시간 낭비로 변하는 일에 빠지기가 얼마나 쉬운지 모릅니다.

    나를 앞으로 나아가게 하고, 문제를 풀고, 배우고, 다른 사람을 돕고, 실력을 갈고닦는 일을 하세요. 그런 활동에는 어떤 노력을 들이든 돌려받는 것이 있습니다.

  6. SenHeng HN

    저는 좀 특이한 밤 일과가 생겼습니다. 아이들에게 잠자리 동화를 읽어 준 뒤 침대에 들어가 소설책을 집는 대신, 14년 된 Asus eeePC 701(wikipedia.org) 미니 노트북을 켜고 x86 어셈블리어를 짜고 있습니다.

    잠을 망치지 않고 어떻게 이러는지 모르겠습니다. 저는 공인회계사 시험 공부 중인데, 자기 전에 "한 가지만 더" 하면 잠을 완전히 망쳐요. 세법처럼 따분한 것을 공부해도 머리가 흥분해서, 몸과 마음이 아무리 지쳐도 새벽 6시까지 깨어 있게 됩니다.

  7. hn_submit HN

    왜 FASM이 아니라 NASM을 고르는 걸까요? 전부 어셈블리어로만 짠 OS인 KolibriOS를 만든 사람들은 FASM을 택했는데, 이유를 모르겠습니다.

    제가 보기에 어셈블러는 다 비슷비슷하고, 그냥 재미 삼아 직접 하나 만드는 것도 충분히 가능할 것 같습니다.

  8. anonymous908213 HN

    FASM은 써 본 적이 없어서 뭐라고 말할 수는 없습니다만, 어셈블러끼리도 차이가 꽤 큽니다. 각각이 사실상 서로 다른 확장 언어를 위한 (최적화 없는) 컴파일러라고 보면 됩니다. 말 그대로 어셈블만 해 주는 어셈블러는 직접 만들기가 아주 쉽지만, 명령어를 하나하나 손으로 쓰는 건 지루하고 그다지 실용적이지도 않습니다. 진지하게 어셈블리를 쓸 생각이라면 매크로 같은 메타프로그래밍 기능이 필요해집니다. 프로그래머가 존재하는 이유 자체가 지루하고 반복적인 일을 자동화하는 것이고, 더 좋은 어셈블러는 그걸 도와주니까요. 어셈블리를 오래 하다 보면 자기 어셈블러를 만드는 건 메타프로그래밍의 자연스러운 다음 단계입니다. 하지만 그 전에 기존 어셈블러로 먼저 배워서, 자기 작업 방식을 충분히 이해하고 반복을 줄이려면 어떤 도구가 필요한지, 기존 어셈블러의 부족한 점이 무엇인지 알아야 합니다.

  9. hn_submit HN

    굳이 그럴 필요가 있나요? 반복 작업은 CALL로 서브루틴을 만들어 쓰면 되잖아요. 결국 C/C++처럼 코드를 인라인하는 것에 불과한 매크로 기능이 왜 필요하죠? 인라인은 실행 파일도 쓸데없이 키우고요. 쓸 데가 있을 수는 있겠지만, 대부분은 그냥 함수나 서브루틴을 호출하는 편이 낫다고 생각해요.

  10. anonymous908213 HN

    호출에는 오버헤드가 있어서 모든 곳에 쓸 수는 없습니다. 특히 핫 패스에서는 더 그렇습니다. 어셈블리를 쓰는 이유는 애초에 성능 최적화입니다. 하드웨어가 아주 제한적인 환경에서는, 아니 제한적일수록 더더욱, 보통 코드 크기를 내주고 성능을 얻는 쪽을 훨씬 선호합니다.

  11. userbinator HN

    어셈블리를 GDB로 디버깅한다... 참 독특한 선택이네요.

  12. gopalv HN

    Gdb는 원래 코드가 C로 쓰였더라도 어셈블리를 디버깅하기에 아주 훌륭한 디버거입니다.

    저는 코어 덤프를 열 때마다 습관처럼

    (gdb) x/4i $pc

    를 자동으로 입력하곤 했습니다.

    다만 nasm으로 작성해 놓고 디버거에서 gas 스타일 어셈블리를 보면 좀 더 낯설 수는 있겠네요.

  13. stevekemp HN

    "set disassembly-flavor intel"은 제가 gdb를 본격적으로 쓰기 시작했을 때 가장 먼저 한 설정 중 하나였어요.

  14. pjmlp HN

    저는 예전에 제 장난감 L98 컴파일러의 런타임을 Intel 문법에서 AT&T 문법으로 포팅한 적이 있습니다. GAS 하나에만 의존하려는 생각이었죠. 공부 삼아 한 번 해 본 것으로 충분했고, 다시 할 생각은 없습니다.

    공식 문서를 볼 때마다 AT&T 문법으로 머릿속에서 변환해야 하는 것만으로도 수고할 가치가 없습니다.

  15. pjmlp HN

    왜요? 예전에 Timex와 MS-DOS debug로 디버깅하던 고통을 겪고 나서 만난 Turbo Assembler 디버거는 정말 편하게 느껴졌습니다.

  16. gregkb HN

    Turbo Assembler라니요!!! 적어도 제 주변 데모씬에서는 거의 표준이었습니다. 저는 우리 DOS 데모 대부분을 그걸로 만들었어요. 리얼 모드에서 돌아가는 건 뭐든 했죠. 이미 메모리에 올라간 코드를 수정하는 별별 짓까지요... 그러다 (보호 모드를 쓰는) 진짜 32비트 코드로 넘어오면서는 Watcom C+asm 컴파일러가 대세가 됐습니다. 그래도 어셈블리를 손으로 짜기는 했지만, 펜티엄이 나와서 프리페치와 듀얼 파이프라인 실행이 생긴 뒤로는 Watcom C가 꽤 효율적이고 최적화된 코드를 만들어 줘서 어셈블리 코딩은 대부분 사라졌습니다. (나중에 마이크로칩 컨트롤러 프로그래밍에서는 업무로 쓰긴 했습니다.) 향수를 느끼고 싶다면 요즘은 차라리 가상 콘솔을 하나 잡겠습니다. 해상도나 색상 같은 제약만으로도 머리 쓸 거리가 충분해서, 굳이 x86 어셈블리까지 돌아갈 필요가 없거든요. :)

  17. halb HN

    GDB로 어셈블리를 다루는 건 아주 흔한 일입니다. 다만 플러그인과 함께 쓸 때 얘기입니다. 요즘은 주로 소프트웨어를 리버스 엔지니어링하거나, 저수준 메모리 손상 익스플로잇을 테스트할 때 그렇게 합니다.

    인기 있는 gdb 플러그인인 pwndbg의 스크린샷을 보면 어떤 모습인지 잘 알 수 있습니다: pwndbg.re/stable/features

  18. cellsstudio HN

    지난 몇 달간 Claude/Codex를 많이 쓰면서 실력이 꽤 퇴화했다고 느낀 분 계세요?

    이게 기본기로 돌아가서 엔지니어링 실력을 날카롭게 유지하는 좋은 방법 같아요. 저도 비슷한 걸 해 봐야겠어요...

  19. userbinator HN

    평소에 어셈블리를 꾸준히 읽고 쓰던 사람이 아니라면 "퇴화"라고 부르진 않겠습니다.

Hacker News에서 보기 ↗