为什么``printf'printf'printf'%hu%```''''in stack而不是堆栈2?

发布于 2025-01-24 04:12:27 字数 880 浏览 0 评论 0原文

我正在研究组装基础知识,并且经常使用printf(我认为我从C/C ++经验中足够了解)。我遇到了带有2个字节(16位)值的奇怪的事情:

在32位模式下,使用printf(“%hu”,(unsigned short)123) ,我认为它会脱离6个字节从堆栈(4用于格式字符串的地址,为值2)。同时,现实是,地址为4,价值为4。

为什么?%hu等于%u?还是只是剥离值的高2个字节?


一些代码(从C到ASM编译,-O0): https://godbolt.org/z/x167zdon1

        mov     eax, 123
        push    eax
        push    format ; "%hu"
        call    _printf
        add     esp, 4 + 4    ; works

        mov     ax, 123
        push    eax
        push    format ; "%hu"
        call    _printf
        add     esp, 4 + 2    ; doesn't work: print gibberish, as it takes 2 bytes more to display the value....

I am studying assembly basics and I use printf quite often (which I thought I know good enough from C/C++ experience). I came across weird thing with 2 bytes (16 bits) values:

In 32 bit mode, when using printf("%hu", (unsigned short)123), I thought it would take off 6 bytes from stack (4 for address of format string, and 2 for value). Meanwhile reality is, it 4 for address and 4 for value.

Why is that? Is %hu equal to just %u? Or is it just stripping high 2 bytes of the value?


Some code (from C to ASM compiling, -O0):
https://godbolt.org/z/x167zdon1

This works:

        mov     eax, 123
        push    eax
        push    format ; "%hu"
        call    _printf
        add     esp, 4 + 4    ; works

But I thought this should:

        mov     ax, 123
        push    eax
        push    format ; "%hu"
        call    _printf
        add     esp, 4 + 2    ; doesn't work: print gibberish, as it takes 2 bytes more to display the value....

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

少钕鈤記 2025-01-31 04:12:27

不起作用...

当然:您执行了推动EAX,该在堆栈上推动4个字节。因此,您必须再次从堆栈中删除4个字节。

我遇到了带有2个字节(16位)值的怪异事物。

在x86-32代码中,堆栈通常应对齐4。这意味着esp寄存器的值应为4的倍数。

因此,大多数调用约定都需要推动32位值如果函数参数仅为16个字节值。

%hu等于%u?还是只是剥离值的高2个字节?

这取决于呼叫约定和库实现:

使用C编译器必须push的32位数字时,如果参数为16位值,则code> push 一个32位数,库(printf函数)可以以%hu%u相同的方式实现

当使用该数字的上部16位可能具有任何值的情况下,使用呼叫约定时,printf函数当然必须剥离上部2个字节。

编辑

实际上,您在printf示例中具有两个效果:

  1. 正如我已经写的那样,x86-32编译器将通过32位值如果char简短参数是预期的。
  2. 在具有可变数量参数的函数(例如printf)中,必须将类型char> char简短的“附加”参数施加到int由编译器。

假设我们在16位CPU上工作,但是数据类型int长32位。我们有一些功能void Test(简短x,...);

如果我们调用test(A,A);在这种情况下,编译器将将第一个参数作为16位值传递(因为该参数具有数据类型简短)第二个参数为32位值(因为这是一个附加参数)。

假设int是32位数据类型,printf()的其他参数也是如此。

doesn't work ...

Sure: You performed a push eax, which pushes 4 bytes on the stack. For this reason, you have to remove the 4 bytes from the stack again.

I came across weird thing with 2 bytes (16 bits) values.

In x86-32 code, the stack should typically be aligned to 4. This means that the esp register's value shall be a multiple of 4.

For this reason, most calling conventions require pushing a 32-bit value if the function argument is only a 16- or even an 8-byte value.

Is %hu equal to just %u? Or is it just stripping high 2 bytes of the value?

It depends on the calling convention and the library implementation:

When using a calling convention where the C compiler has to push a 32-bit number whose upper 16 bits are 0 if the argument is a 16-bit value, the library (the printf function) may be implemented in a way that %hu is identical to %u.

When a calling convention is used where the upper 16 bits of such a number may have any value, the printf function must strip the upper 2 bytes, of course.

Edit

Actually, you have two effects in the printf example:

  1. As I have already written, an x86-32 compiler will pass 32-bit values to a function if a char or short argument is expected.
  2. In functions with a variable number of arguments (such as printf), the "additional" arguments of the type char or short must be cast to int by the compiler.

Let's assume we work on a 16-bit CPU but the data type int is 32 bits long. And we have some function void test(short x, ...);.

If we call test(a, a); in this situation, the compiler will pass the first argument as 16-bit value (because the argument has the data type short) and the second argument as 32-bit value (because it is an additional argument).

The same is the case for the additional arguments of printf() - assuming that int is a 32-bit data type.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文