C语言中的hello world程序的汇编代码

时间:2017-12-22 22:53:55

标签: c assembly visual-c++ x86 msvcrt

以下是hello world程序的示例代码:

#include <stdio.h>


int main(void)
{
    printf("Hello, world!\n");
    return 0;
}

这是对象文件的反汇编:我有:

File Type: COFF OBJECT

main:
  0000000000000000: 48 83 EC 28        sub         rsp,28h
  0000000000000016: C3                 ret

__local_stdio_printf_options:
  0000000000000000: 48 8D 05 00 00 00  lea         rax,[?_OptionsStorage@?1??__local_stdio_printf_options@@9@9]
                    00
  0000000000000007: C3                 ret

_vfprintf_l:
  0000000000000000: 4C 89 4C 24 20     mov         qword ptr [rsp+20h],r9
  0000000000000014: 48 83 EC 38        sub         rsp,38h
  0000000000000018: E8 00 00 00 00     call        __local_stdio_printf_options
  0000000000000039: E8 00 00 00 00     call        __stdio_common_vfprintf
  000000000000003E: 48 83 C4 38        add         rsp,38h
  0000000000000042: C3                 ret

printf:
  0000000000000000: 48 89 4C 24 08     mov         qword ptr [rsp+8],rcx
  0000000000000027: E8 00 00 00 00     call        __acrt_iob_func
  000000000000002C: 4C 8B 4C 24 28     mov         r9,qword ptr [rsp+28h]
  000000000000003C: E8 00 00 00 00     call        _vfprintf_l
  0000000000000041: 89 44 24 20        mov         dword ptr [rsp+20h],eax
  000000000000004E: 8B 44 24 20        mov         eax,dword ptr [rsp+20h]
  0000000000000056: C3                 ret

printf函数中,我们还有两个函数调用:__acrt_iob_func_vfprintf_l

  1. 第一个功能到底是做什么的?

  2. 我们如何在目标文件中使用_vprintf_l函数?

  3. 详细解释将不胜感激。

    已编译: cl /TC main.cpp

    反汇编: dumpbin /disasm main.obj

    PS:我部分删除了汇编代码,以便发布问题。

3 个答案:

答案 0 :(得分:2)

VS2015及更高版本现在包含头文件中printf的部分代码(以前它只是一个基于库的函数)。对于C / C ++,它不是一个问题,但在我的情况下,对于本来只有汇编的项目,我现在在项目中包含一个调用printf的小C源文件,它生成所需的代码以便汇编代码可以调用printf而不包含与包含头代码相关的所有其他内容。

  

第一个功能到底是做什么的?

__ local_stdio_printf_options返回一个指向静态整数的指针,该整数用作__stdio_common_vfprintf的输入。

  

我们如何在目标文件中使用_vprintf_l函数?

这是因为printf代码的一部分现在包含在头文件中,之前所有printf都包含在标准C库中。

这是当前本地printf实例所包含内容的片段。我没有推断出这两个定义,但最终结果可以在下面的汇编代码中看到。

__inline unsigned __int64* __CRTDECL __local_stdio_printf_options(void)
{
    static unsigned __int64 _OptionsStorage;
    return &_OptionsStorage;
}

#define _CRT_INTERNAL_LOCAL_PRINTF_OPTIONS (*__local_stdio_printf_options())

_CRT_STDIO_INLINE int __CRTDECL _vfprintf_l(
    _Inout_  FILE*       const _Stream,
    _In_z_   char const* const _Format,
    _In_opt_ _locale_t   const _Locale,
             va_list           _ArgList
    )
{
    return __stdio_common_vfprintf(_CRT_INTERNAL_LOCAL_PRINTF_OPTIONS, _Stream, _Format, _Locale, _ArgList);
}

_CRT_STDIO_INLINE int __CRTDECL printf(
    _In_z_ _Printf_format_string_ char const* const _Format,
    ...)
{
    int _Result;
    va_list _ArgList;
    __crt_va_start(_ArgList, _Format);  /* this is a define */
    _Result = _vfprintf_l(stdout, _Format, NULL, _ArgList);
    __crt_va_end(_ArgList);             /* this is a define */
    return _Result;
}

VS2015的汇编输出片段使得它更加清晰。同样,请记住,所有这些都是printf的内部,并且可能会随着Visual Studio的更高版本而改变。

CONST   SEGMENT
??_C@_0P@DOOKNNID@Hello?0?5world?$CB?6?$AA@ DB 'Hello, world!', 0aH, 00H
CONST   ENDS

_TEXT   SEGMENT
__local_stdio_printf_options PROC
        lea     rax, OFFSET FLAT:?_OptionsStorage@?1??__local_stdio_printf_options@@9@9 ;static variable
        ret     0
__local_stdio_printf_options ENDP

_vfprintf_l PROC
;       ...
        call    __local_stdio_printf_options            ;local instance
;       ...
        call    QWORD PTR __imp___stdio_common_vfprintf ;library function
;       ...
        ret     0
_vfprintf_l ENDP

printf  PROC
;       ...
        call    QWORD PTR __imp___acrt_iob_func         ;library function
        mov     rbx, rax
        call    __local_stdio_printf_options            ;local instance
;       ...
        call    QWORD PTR __imp___stdio_common_vfprintf ;library function
        ret     0
;       ...
printf  ENDP

main    PROC
        sub     rsp, 40                                 ; 00000028H
        lea     rcx, OFFSET FLAT:??_C@_0P@DOOKNNID@Hello?0?5world?$CB?6?$AA@
        call    printf
        xor     eax, eax
        add     rsp, 40                                 ; 00000028H
        ret     0
main    ENDP
_TEXT   ENDS

这是VS先前版本的程序集输出,其中printf只是一个库函数(__imp_printf):

CONST   SEGMENT
??_C@_0P@DOOKNNID@Hello?0?5world?$CB?6?$AA@ DB 'Hello, world!', 0aH, 00H
CONST   ENDS

_TEXT   SEGMENT
main    PROC
        sub     rsp, 40                                 ; 00000028H
        lea     rcx, OFFSET FLAT:??_C@_0P@DOOKNNID@Hello?0?5world?$CB?6?$AA@
        call    QWORD PTR __imp_printf
        xor     eax, eax
        add     rsp, 40                                 ; 00000028H
        ret     0
main    ENDP
_TEXT   ENDS

答案 1 :(得分:1)

__acrt_iob_func是Microsoft Visual C中的内部 C 运行时(CRT)函数。

  

[They] are used internally to implement the standard C and C++ libraries

推测使用__acrt_iob_func

_acrt_iob_func可能用于设置基本I / O ,例如分配 stdin stdout stderr 以及

真正看不到的东西

vprintf

printf(3)通常是围绕vprintf(3)的包装函数,它将va_list作为参数

答案 2 :(得分:-2)

编译器使用内置函数,主要是在linux下通过libc。这个内部版本可以在多个平台上运行,也有一些优化。如果您查询谷歌,您可以查看libc的源代码。 您还可以使用调试器跟踪函数,并确切了解它正在做什么。

总结一下,这取决于你的编译器和库的实现。你好世界也可以手工做得更短。