Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 返回主vs_start中的值_C_Assembly_X86 64_Main - Fatal编程技术网

C 返回主vs_start中的值

C 返回主vs_start中的值,c,assembly,x86-64,main,C,Assembly,X86 64,Main,注意,这个问题在这里已经有了类似的答案,我想指出: 然而,这个问题更多地询问了它们的返回格式以及它们之间的关系(我认为上面的问题并没有完全涉及到这一点) \u start和main之间有什么区别?在我看来,ld使用\u start,但是gcc使用main作为入口点。我注意到的另一个区别是,main似乎返回%rax中的值,而\u start返回%rbx中的值 以下是我看到这一点的两种方式的示例: .globl _start _start: mov $1, %rax mov

注意,这个问题在这里已经有了类似的答案,我想指出:

然而,这个问题更多地询问了它们的返回格式以及它们之间的关系(我认为上面的问题并没有完全涉及到这一点)


\u start
main
之间有什么区别?在我看来,
ld
使用
\u start
,但是
gcc
使用
main
作为入口点。我注意到的另一个区别是,
main
似乎返回
%rax
中的值,而
\u start
返回
%rbx
中的值

以下是我看到这一点的两种方式的示例:

.globl _start
_start:
    mov $1, %rax
    mov $2, %rbx
    int $0x80
要运行它:

$ as script.s -o script.o; ld script.o -o script; ./script; echo $?
# 2
$ gcc script.s -o script; ./script; echo $?
3

另一方面:

.globl main
main:
    mov $3, %rax
    ret
要运行它:

$ as script.s -o script.o; ld script.o -o script; ./script; echo $?
# 2
$ gcc script.s -o script; ./script; echo $?
3

这两种方法有什么区别?
main
是否会在某个地方自动调用
\u start
,或者它们之间的关系如何?为什么一个在
rbx
中返回值,而另一个在
rax
中返回值?

TL:DR:函数返回值和系统调用参数使用单独的寄存器,因为它们完全不相关


当您使用
gcc
进行编译时,它会链接定义
\u start
的CRT启动代码
\u start
(间接)调用
main
,并将
main
的返回值(main留在EAX中)传递给
exit()
库函数。(在执行任何必要的libc清理(如刷新stdio缓冲区)后,它最终会发出一个退出系统调用。)

另请参见-这与您所做的完全类似,只是您使用的是绕过libc清理的
\u exit()
,而不是
exit()

根据32位系统调用ABI()在EBX中获取其参数它不是函数的返回值,而是进程退出状态。有关系统调用的更多信息,请参阅

请注意,
\u start
不是一个函数;从这个意义上讲,它不能返回,因为堆栈上没有返回地址您正在采用一种随意的描述,如“返回操作系统”,并将其与函数的“返回值”混为一谈。如果需要,您可以从
main
调用
exit
,但不能从
\start
调用
ret

EAX是函数调用约定中
int
大小的值的返回值寄存器。(RAX的高32位被忽略,因为
main
返回
int
。但是,
$?
退出状态只能获得传递给
exit()
的值的低8位)

相关的:

  • 解释为什么应该使用
    syscall
    ,并显示系统调用后内核内部发生的一些内核方面的情况

\u start是二进制文件的入口点。Main是C代码的入口点

_start特定于工具链,main()特定于语言

你不能简单地开始执行编译好的C代码,你需要一个引导程序,一些代码可以准备像这样的高级语言所需要的最少的东西,其他语言有更长的需求列表,但对于C语言,您需要通过加载程序(如果在操作系统上)或引导程序,或同时通过堆栈指针的解决方案,以便有一个堆栈,初始化读/写全局数据(通常称为.data),并将归零(通常称为.bss)数据归零。然后引导程序可以调用main()

因为大多数代码在某些操作系统上运行,并且操作系统可以/确实将代码加载到ram中,所以它不需要硬入口点要求,就像在有硬入口点或硬向量表地址的情况下引导处理器一样。因此gnu足够灵活,一些操作系统足够灵活,代码的入口点不必是二进制文件中的第一个机器代码。现在,这并不意味着_start表示入口点本身,因为您需要告诉链接器入口点条目(_start),例如,如果您使用gnu ld的链接器脚本。但是这些工具确实希望找到一个名为_start的标签,如果链接器没有找到,那么它会发出警告,它会继续运行,但会发出警告

main()特定于C语言作为C入口点,引导程序在完成其工作并准备运行编译的C代码后调用该标签

如果加载到ram中,并且二进制文件格式支持它,并且操作系统的加载程序支持它,则二进制文件的入口点可以在二进制文件中的任何位置,如二进制文件所示

您可以将_start视为二进制代码的入口点,将main视为已编译C代码的入口点

C函数的返回是由C编译器使用的调用约定定义的,编译器作者可以自由地做任何他们想做的事情,但现代他们通常遵循目标定义(ARM、x86、MIPS等)定义的约定。因此,C调用约定确切地定义了如何根据对象返回某些内容,因此int main()是int的返回,但是float myfun()在约定中可能有不同的规则

二进制文件的返回(如果可以返回的话)由独立于高级语言的操作系统或操作环境定义。因此,在x86处理器上的mac上,规则可能是一回事,在x86上的Windows上,规则可能是另一回事,在同一x86上的Ubuntu Linux上,规则可能是另一回事,bsd,另一个,可能不是但Mint Linux,等等

规则和系统调用特定于操作系统,而不是处理器或计算机,当然也不是不直接接触操作系统的高级语言(h
Disassembly of section .init:

00000000000004b8 <_init>:
 4b8:   48 83 ec 08             sub    $0x8,%rsp
 4bc:   48 8b 05 25 0b 20 00    mov    0x200b25(%rip),%rax        # 200fe8 <__gmon_start__>
 4c3:   48 85 c0                test   %rax,%rax
 4c6:   74 02                   je     4ca <_init+0x12>
 4c8:   ff d0                   callq  *%rax
 4ca:   48 83 c4 08             add    $0x8,%rsp
 4ce:   c3                      retq   

...

Disassembly of section .text:

00000000000004f0 <main>:
 4f0:   b8 05 00 00 00          mov    $0x5,%eax
 4f5:   c3                      retq   
 4f6:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
 4fd:   00 00 00 

...

0000000000000500 <_start>:
 500:   31 ed                   xor    %ebp,%ebp
 502:   49 89 d1                mov    %rdx,%r9
 505:   5e                      pop    %rsi
 506:   48 89 e2                mov    %rsp,%rdx
 509:   48 83 e4 f0             and    $0xfffffffffffffff0,%rsp
 50d:   50                      push   %rax
 50e:   54                      push   %rsp
 50f:   4c 8d 05 6a 01 00 00    lea    0x16a(%rip),%r8        # 680 <__libc_csu_fini>
 516:   48 8d 0d f3 00 00 00    lea    0xf3(%rip),%rcx        # 610 <__libc_csu_init>
 51d:   48 8d 3d cc ff ff ff    lea    -0x34(%rip),%rdi        # 4f0 <main>
 524:   ff 15 b6 0a 20 00       callq  *0x200ab6(%rip)        # 200fe0 <__libc_start_main@GLIBC_2.2.5>
 52a:   f4                      hlt    
 52b:   0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)