【问题标题】:Why my Function is receiving wrong pointer, and stack is corrupted?为什么我的函数接收到错误的指针,并且堆栈已损坏?
【发布时间】:2021-04-14 01:17:16
【问题描述】:

我在学校一直在做一个定制的操作系统项目,当我开始用 C++ 编码时,我遇到了一个巨大的问题:

我在汇编中构建了一个自定义的 put_char 函数,它基本上需要一个地址和一个 Dword 值并将其保存在内存中。我用的是Qemu虚拟机,0xb8000是Screen memory start (SCREEN_START)

如果我在 CPP 中运行代码:

put_char(SCREEN_START, 0x2f562f56)

(0x2f202f56 是 "/V/V") 它将“VV”打印到屏幕上,因此该功能本身确实有效。

put_chars 代码:

put_char:

push ebp    ; save the prior EBP value
mov ebp, esp

mov ebx, edi;
mov edx, esi;

mov dword [ebx], edx

xor eax,eax

pop ebp     ; minimal cleanup
ret

但是当我绑定从数组中打印一个字符时,就会出现问题: 当我尝试将字符串 (char *) 传递给函数时,它会发送错误的值。

void pp(char hello[])
{
    for (int i = 0; i < 7; i++)
    {
        put_char(SCREEN_START + i*4, hello[i] );
    }
}

global void kernel_main()
{
    pp("Hello!");
}

屏幕每次打印不同的值,而且从来不是“你好!”... 例如它只打印空格...

根据我的阅读,当堆栈损坏时会发生这种情况,但我没有在我的任何代码中使用堆栈,尤其是汇编代码。

不太确定如何解决这个问题,尝试了不同的方法,比如构建一个结构或一个类,将其作为 char* 而不是 char[] 传递,制作一个常量字符串以在函数外部打印……没有任何效果,我什至尝试发送int数组,但没有成功。

如果有人可以提供帮助,请告诉我!真的很需要!

【问题讨论】:

  • 注意:如果发送即时值,put_char 函数可以正常工作...
  • I've been working on a customized operating system project in school 这在学校看起来不太明智。
  • 从表面上看,您的问题可能是任何问题,从简单的参数顺序错误到 put_chatr()(第一个字符,然后是数字)到复杂的 put_char()不工作。如果您没有向我们展示更多内容,并且如果您没有更详细地解释会发生什么,(“打印不同的值”是不够的)我们无法判断。
  • 另外,为了将来参考,当在 stackoverflow 上提问时,只要坚持事实并跳过关于正在发生的事情的理论。你的函数接收到错误的指针是一个理论。堆栈被破坏是一个理论。这些理论都无关紧要。相关但您没有展示的是put_char() 的原型以及put_char() 的实现或至少是文档。
  • 我已经编辑了这个问题。看看吧。

标签: c++ function pointers


【解决方案1】:

DWORD 是无符号的 32 位数据单元,而 C 编程语言中的 char 是大小正好为 8 位的数据类型。所以put_char 正在打印 32 位,而数组中的每个字符都是 8 位,所以它正在打印垃圾。您应该使用与 put_char 不同的函数,以便一次准确地打印 8 位,或者创建 32 位无符号整数数组。

【讨论】:

  • 这些我都知道,这不是问题所在。我已经添加到问题中,您现在可以看到 put_char 函数...
  • 您是否尝试过在代码中使用put_char(SCREEN_START + i*4, *hello[i] );?它可能只是获取hello[i] 的地址,而不是存储在该地址中的数据。
  • 感谢帮助,问题原来很简单很愚蠢:我忘了在bootloader中为系统设置堆栈。
【解决方案2】:

Intel Assembly 中put_char() 的定义如上所示假定传递给它的第一个参数在寄存器edi 中,第二个参数在寄存器中esi。 OP 仍然未能在 C++ 中显示 put_char() 的原型,但可以合理地假设没有指定调用约定,因此这些当函数在特定场景中被调用时,寄存器中包含这些值纯属巧合。这意味着当这个函数用于不同的场景时,这些寄存器包含不同的值,所以结果就是观察到的故障。

为了解决这个问题,应该在原型中指定函数的调用约定,(可能是cdeclstdcall,)然后很可能必须修改程序集以遵循这个约定,这意味着每个参数的值可能需要从ebp 的某个偏移量中获取。如需更多信息,请参阅Stack Overflow: What does “cdecl” stand for?

【讨论】:

  • 感谢您的帮助,我马上试试看。
  • 祝你好运!让我们知道发生了什么。
  • 但实际上,现在我再次查看编辑后的问题,在我看来,柴坦亚的回答可能也是正确的。 0x2f562f56DWORDmov dword [ebx], edx 存储 DWORD。您仍然未能准确告诉我们它打印了哪些“不同的值”,但hello[i] 是一个字符,这势必会导致问题。
  • 此外,您可以将DWORDchar 传递给您的函数这一事实可能意味着您根本没有定义原型,(但到目前为止您还没有这么说,) 或者您收到编译器警告但您忽略了它们,(这肯定会导致失败),或者在没有启用足够数量的编译器警告的情况下尝试实际从事编程艺术。 (这也保证会导致失败。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-11
  • 1970-01-01
  • 2015-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多