어셈블러를 디버깅할 때 내 애플리케이션 프로그래머 본능이 실패했습니다.

hackernews | | 💼 비즈니스
#os 개발 #tip #디버깅 #어셈블러 #프로그래밍
원문 출처: hackernews · Genesis Park에서 요약 및 분석

요약

1. **Analyze the Request:** * **Role:** News summarization expert. * **Task:** Summarize the provided article concisely. * **Length:** 2-4 sentences. * **Content Focus:** Most important information. * **Constraints:** Do not copy-paste, do not just restate the title, add new info. * **Language:** English. * **Input:** Title ("My application programmer instincts failed when debugging assembler") and empty Article Text. 2. **Analyze the Input:** * **Title:** "My application programmer instincts failed when debugging assembler". This suggests a narrative about a developer encountering difficulty moving from high-level languages (application programming) to low-level assembly language debugging. * **Article Text:** The provided text is missing (it just repeats the title under "Article Text"). 3. **Identify the Problem:** I cannot summarize an article that isn't there. The user provided the title but the content body is effectively empty or just a repetition of the title. 4. **Determine the Strategy:** * Option A: Hallucinate a summary based *only* on the title. (Bad idea, likely to be inaccurate). * Option B: Refuse the task because the text is missing. (Strict adherence to "news summarization expert" who needs facts). * Option C: Look closer at the prompt. Is there hidden text? No. * Option D: Assume the user made a mistake and didn't paste the text. I should inform them I need the text to proceed. *Self-Correction:* Wait, usually in these prompts, the "Article Text" section is populated. Since it's not, I must assume I cannot generate a summary of *content* that doesn't exist. However, looking at the prompt structure, it looks like

본문

I’ve had a smidge of extra time with my recent unemployment, so to stay sharp and learn a few new things I followed Seiya Nuta’s guide to building an Operating System in 1,000 Lines. I’m not an OS programmer, my life is normally spent at high-level application programming. (The closest I come to the CPU is the week I spent trying to internalize the flow of those crazy speculative execution hacks.) Assembler is easy enough to write, that wasn’t the problem. The problem was when I encountered problems. My years of debugging application-level code has led to a pile of instincts that just failed me when debugging assembler-level bugs. These are the three places I had the biggest problems debugging. Big error #1 â I forgot a ret in a naked assembler function# I forgot the ret in a naked assembler function. It didn’t return to its caller. What happened next is both fun and obviousâbut only when you know that you missed a ret . That functionâlet’s call it the first functionâdidn’t return to its caller, so execution just went to the next function in the file. The input arguments were whatever happened to be in the a0 and a1 registers. And when that second function returned, it used the caller information that was still available in the ra register, and it returned to where the first function was called from. This is something that just doesn’t happen in application programming, which meant that I had a heck of a time debugging it. It was even harder to debug because those two functions were related. They were next to each other in the file, of course they were related. I saw that the second function was doing strange stuff, and I was expecting it to be called around that time, so I focused on that error. My application-programmer brain went like this: Why was it failing? It was sometimes being called with junk parameters, and it was being called more often than it should be. Why? Look at the caller. Why? Investigate the calling site. Investigate any loops. Move up the calling tree. Repeat. Repeat. Repeat. Which sent me nowhere near the problem. Everything went nowhere until I read the compiled assembler and started manually tracing execution. Lesson 1: Application code is (mostly) about logical abstractions. OS code isn’t (always) about that. Debugging problems in OS code may be about just looking at adjacent assembler code. (Addendum: This was around the process-creation code, which made things even weirder.) Big error #2 â incorrect types in a packed struct# Another error was an incorrect type inside a packed struct. It only needed 16 bits, but I was copying and pasting a previous line and gave it 32 bits. In application programming, the size of the variable really doesn’t matter much to me, it’s almost entirely abstracted away in dynamic languages. I’ve spent a long time in the mindset that the size of types is on the other side of a certain abstraction, and that abstraction will nicely fail to compile if I make a mistake. I don’t think about it. Types in C code are a lot more about how much space the variable takes up, with a bit of semantics on top. There’s no abstraction. Even with one struct member having too much space allocated to it, the whole thing still compiled correctly, and all my tests in the C code showed it working. But the struct was also being accessed in assembler. In assembler I was manually calculating the offsets from the struct location, using the sizes in the tutorial, and I didn’t make any silly mistakes while copying and pasting code here, which meant that suddenly that incorrect type caused a failure. It was easy to printf and see that the values of the structs were correct, but that was C’s view of the struct. Lesson 2 Lesson 1, again: There is no abstraction. (Addendum: One thing I’ve learned about assembler code is that it just “goes forward” in a way that other languages don’t. In any pile of Rust code I have so many defined types and conversions and error handlers that errors are noted and bubble up right away. The nature of a good abstraction.) #3 (a smaller one): the __attribute__ typo that compiled# I also learned how forgiving C parsing can be: __attribute((foo)) compiled and ran, even though the correct syntax is __attribute__((foo)) . I got no compilation failure to tell me that anything went wrong. In Sum# Abstractions. They don’t exist in assembler. Memory is read from registers and the stack and written to registers and the stack. It’s something that I know in my rational brain, and I was happily coding with that in mind. But when problems came up, I never realized how much I run on instinct and past patterns. I’ve been pretty good at debugging applications in my career, it’s what I’ve done most of. But my application-coded debugging brain kept looking at abstractions like they would provide all the answers. I rationally knew that the abstractions wouldn’t help, but my instincts hadn’t gotten the message. I’m not an OS programmer or a low-level programmer. I don’t know if

Genesis Park 편집팀이 AI를 활용하여 작성한 분석입니다. 원문은 출처 링크를 통해 확인할 수 있습니다.

공유

관련 저널 읽기

전체 보기 →