You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

视频内存偏移计算为何差1?自制OS字符显示异常排查

Hey there! I’ve run into this exact quirk when messing with VGA text mode during my own OS dev projects—let’s break down what’s likely going wrong here and how to debug it:

1. You’re probably mismatching pointer type and offset math

This is the #1 mistake with VGA text mode:

  • If video_memory is declared as an unsigned short* (each element holds a full 2-byte character+attribute pair), your offset should just be (row * 80) + col—no need to multiply by 2.
  • But you said you’re using unsigned char*, which means each index is a single byte. So your formula ((row * 80) + col) * 2 is technically correct… unless you accidentally mixed up the pointer type in code, or forgot to multiply (or multiplied twice) somewhere.

For example, if you had a leftover unsigned short* declaration but kept the *2 in your offset, you’d be addressing 0xb8000 + ((row*80+col)*2)*2—that’s 4x the intended offset, which would dump your character in a totally random spot.

2. Variable type truncation is sneaking in

If row and col are defined as 8-bit types (like char or unsigned char), you might be hitting unexpected truncation during calculations:

  • row * 80 will get promoted to int automatically, but if you store the final offset in an 8-bit variable (e.g., char offset instead of int offset), it’ll get chopped down to 8 bits. Even with row=0, this could cause weird behavior if other parts of the calculation overflow 8 bits.
  • Fix this by explicitly declaring offset as an int (or unsigned int) to keep the full 32-bit value during calculations. You can also cast row and col to int in the formula to avoid implicit promotions:
    int offset = (((int)row * 80) + (int)col) * 2;
    

3. Let’s dig into that disassembly

Your kernel’s disassembly holds the smoking gun—focus on these steps:

  • Parameter passing: Double-check that row and col are being loaded correctly. Did the calling convention mix up their order? (C uses right-to-left stack pushing, so if your function expects (char c, int row, int col), the stack should have col, row, c on top.)
  • Offset calculation: Look for instructions like mul (for row*80), add (for +col), and shl (for *2). Is the shl missing? Did it use an arithmetic shift (sar) instead of logical shift? Any sign extension weirdness (e.g., 16-bit registers being sign-extended to 32-bit instead of zero-extended)?
  • Addressing: Is the final offset correctly added to 0xb8000? If you see something like add eax, 0xb8000 where eax holds your offset, that’s good—but if eax has a truncated or wrong value, that’s the issue.

4. Don’t forget the attribute byte

Even though your clear-screen loop works, double-check that you’re setting the attribute byte when printing 'X':

  • If you only do video_memory[offset] = 'X' without setting video_memory[offset + 1] = 0x07 (black background, white text), the attribute byte will be whatever random value was in memory. For row=0 col=0, that might be 0x00 (black on black), making the character invisible. For row=0 col=1, maybe the clear-screen loop already set that attribute byte to 0x07, so the character shows up—but in the wrong spot because your offset is off.

Quick sanity checks to narrow it down

  1. Hardcode the offset: Try video_memory[0] = 'X'; video_memory[1] = 0x07;—if the top-left corner shows 'X', your pointer and memory access are working, so the problem is definitely in your offset calculation.
  2. Print the offset value: Debug by writing the offset number to a fixed screen position (e.g., row=2, col=0). See what value comes out for row=0 col=0 vs row=0 col=1—does it match 0 and 2 like you expect?
  3. Simplify the formula: Replace the dynamic calculation with hardcoded values one step at a time to isolate where it breaks.

内容的提问来源于stack exchange,提问作者Jakeman582

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:25:44