【问题标题】:Printing a value to console avoiding the usage of standard libraries将值打印到控制台,避免使用标准库
【发布时间】:2021-08-26 00:27:04
【问题描述】:

我面临着在不使用任何库的情况下(在控制台中)打印值的问题。我试图通过主函数的返回值来做到这一点,但似乎没有办法在不使用 printf() 的情况下在控制台中显示函数的返回值。我正在寻找一条建议,所以请随意“集思广益”。欢迎任何想法,希望您能帮助我并在此之前感谢您。

【问题讨论】:

  • 只有实现提供的功能才有可能。

标签: c printf c-standard-library


【解决方案1】:

从技术上讲,write(注意 write 而不是 fwrite)不是库函数,而是系统调用。 stdout(将出现在屏幕上),如果您能够使用write 找到它的文件描述符编号(提示提示,STDOUT_FILENO),则可以写入。

希望对您有所帮助!如果您需要更多指导,请随时发表评论!

【讨论】:

  • 总是很高兴解释如何通过定义的宏 STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO 提供标准文件描述符编号 0, 1, 2。您暗示了这一点,但始终要明确文件描述符和文件流指针之间的区别(例如FILE*)。话虽如此,你肯定为他提供了很好的信息来跟进。
  • @David 这是真的,但似乎这是一个家庭作业问题,所以我想在将他们指向 POSIX IO API 的方向后让他们进行一些挖掘;)
  • 没有分歧,但是添加定义和数字仍然可以理解文件描述符的使用、系统调用的使用和验证(当遇到void*write() 的参数时,这可能会令人生畏@ 987654332@
  • 你说得对,米切尔,这是一个家庭作业问题。我将在那里进行一些挖掘以找出解决方案,但您的信息非常有用。谢谢!
【解决方案2】:

好吧,当您说 write() 时,您所说的“技术上”仍然是标准库中的“技术上”(尽管它可能在 .h 文件中具有一些宏魔法,具体取决于您的编译器)。存在调用每个系统调用的存根函数。

“技术上”你需要知道你的 ABI 并且你需要知道如何在你的编译器中调用那个 ABI。然后你需要(通常,对于大多数 ABIs)当前写入的系统调用号是多少等等。

在 linux 上查找它(这不是我的家乡,但它有可能是你的) SYS_WRITE 是 linux 上的系统调用 #1。你把那个放在 %rax 中,fd 放在 %rdi 中,缓冲区指针放在 %rsi 中,字符数放在 %rdx 中。

所以我们开始:

mov edx,4       ; message length
mov ecx,msg     ; message to write
mov ebx,1       ; file descriptor (stdout)
mov eax,4       ; system call number (sys_write)
int 0x80        ; call kernel

那些在家阅读的人可能记得你的 BIOS 曾经说过一些关于 INT 80 的内容。 INT 80 相同。

现在您只需将该程序集放入您的 C 文件中。看起来像 gcc 你使用 asm

所以...

main()
{
__asm__("mov    edx,4       ; message length"
        "mov    ecx,msg     ; message to write"
        "mov    ebx,1       ; file descriptor (stdout)"
        "mov    eax,4       ; system call number (sys_write)"
        "int    0x80        ; call kernel");
}

现在...我不会在这里告诉您如何将您的 C 字符串放入寄存器,但我再次说“技术上”...

注意:另外,请注意,我从这里的两个不同示例中复制了一些代码来说明我的观点。 X86 上的寄存器名称一团糟,我认为该段落使用的命名约定与代码 sn-p 不同。

NB2:为了更加迂腐,“技术上”crt.o 可能被认为是标准库。这取决于。有时它也是一个链接器脚本。这当然是您的编译器工具链为您提供的东西。我不打算在这里复制它,但对于您感兴趣的任何平台,谷歌“最小二进制”或类似的东西。很多人都为他们的“频道”做过这种事情......

【讨论】:

  • 这是对 GCC 内联汇编的不安全使用;编译器不希望您在不通知它的情况下修改随机寄存器。请参阅stackoverflow.com/questions/5131568/… 了解如何正确执行此操作。我知道这只是一个插图,但它已经足够接近工作,有人可能会真正尝试使用它。
  • 欣赏它,这是我所期待的那种“头脑风暴”。祝你好运!
  • 是的...我意识到内特。在某种程度上,这不是所问问题的一部分。就其本身而言,可能甚至不是请求者想要的答案。我喜欢去兔子洞。这项工作的障碍: 1. 照 Nate 所说的去做。可能无关紧要,因为 main 什么都不做。我想 main 的返回可能是系统调用的返回......或者 gcc 可能会踩到它。 2. 您需要将字符串的地址放入程序集 msg 符号中。在汇编中声明它会做到这一点。在 C 中将其声明为 extern 可能 这样做。
  • 3.看来 gcc 使用“其他”汇编语法。同样,“linux”和“gcc”不是我的果酱。
  • (呵呵...只是阅读有关家庭作业问题的大帖子。我想这也是我有点讨厌。如果教授分配给我,我可能会按照我指定的路线上交一个工作版本。我可能会试图弄清楚如何让 C 在没有 crt.o 的情况下运行(至少现在 --- 我不确定我是否了解 crt。 o 在大学里(但我确实知道系统调用)))
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-02
  • 1970-01-01
  • 2011-01-30
  • 2016-07-20
  • 1970-01-01
相关资源
最近更新 更多