充分了解流,以及它们如何与程序交互

时间:2018-01-15 23:27:05

标签: c unix stream operating-system

我对流的了解:

从我要告诉我们的操作系统,以便所有程序都可以使用预先连接的I / O和错误流;他们只需要访问/调用。在C中,我们有stdio.h,它是一个头文件,包含使用这些流的各种函数和变量;并建立流和我们的程序之间的联系。流始终存在,但头文件stdio.h为我们的程序提供指令/生成函数以利用它们。这一切都正确吗?在我们必须手动建立这些流之前,这些流是如何建立的?

什么让我感到困惑:

来自维基百科的

1 - " Unix的一些突破性进展之一是抽象设备,这使得程序无需知道或关心它正在通信什么类型的设备与" "在Unix之前的大多数操作系统中,程序必须显式连接到适当的输入和输出设备......较旧的操作系统强制程序员采用记录结构,并且经常是非正交数据语义和设备控制。 "

以上是什么意思?

来自维基百科的

2 - "另一个Unix突破是默认情况下分别自动将输入和输出关联到终端键盘和终端显示 - 程序(和程序员)绝对没有做任何事情为典型的输入过程输出程序建立输入和输出(除非它选择了不同的范例)。 相比之下,以前的操作系统通常需要一些通常很复杂的作业控制语言来建立联系,或者等同的负担必须由程序来协调。"

你能扩展一下吗?

TLDR-我对流的理解是否正确?您能否更深入地解释在Unix之前如何建立流?最后,有这些问题的人应该通过什么资源来进一步理解流?

1 个答案:

答案 0 :(得分:1)

我不太确定你在问什么。

如果你真的对STREAMS,他们的类型,历史等感兴趣,我推荐 这篇来自Linux Journal的文章:LiS: Linux STREAMS

  

我们有stdio.h这是一个包含各种函数和变量的头文件   与这些溪流;并在流和我们的程序之间建立联系。

不完全,stdio.h是一个声明结构(如FILE),函数(fprintf)的头文件, 全局变量(stdin)等,请参阅man 0p stdio.h整体 此头文件的文档。打开,阅读,写作,结束,所有这些 事情是由程序完成的,而不是头文件。这些都是 在你的标准C库中实现,对于glibc来说就是Linux。什么时候 你建立一个程序,你通常将它与glibc链接起来 提供所有这些功能和更多。

看看这个简单的程序:

#include <stdio.h>

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

在C中,程序的入口点是main函数,但是这是 当新程序出现时,操作系统要调用的第一个函数 执行。 objdump显示:

$ objdump -S printf

printf:     file format elf64-x86-64


Disassembly of section .init:

0000000000000550 <_init>:
 550:   48 83 ec 08             sub    $0x8,%rsp
 554:   48 8b 05 85 0a 20 00    mov    0x200a85(%rip),%rax        # 200fe0 <__gmon_start__>
 55b:   48 85 c0                test   %rax,%rax
 55e:   74 02                   je     562 <_init+0x12>
 560:   ff d0                   callq  *%rax
 562:   48 83 c4 08             add    $0x8,%rsp
 566:   c3                      retq   

Disassembly of section .plt:

0000000000000570 <.plt>:
 570:   ff 35 92 0a 20 00       pushq  0x200a92(%rip)        # 201008 <_GLOBAL_OFFSET_TABLE_+0x8>
 576:   ff 25 94 0a 20 00       jmpq   *0x200a94(%rip)        # 201010 <_GLOBAL_OFFSET_TABLE_+0x10>
 57c:   0f 1f 40 00             nopl   0x0(%rax)

0000000000000580 <fwrite@plt>:
 580:   ff 25 92 0a 20 00       jmpq   *0x200a92(%rip)        # 201018 <fwrite@GLIBC_2.2.5>
 586:   68 00 00 00 00          pushq  $0x0
 58b:   e9 e0 ff ff ff          jmpq   570 <.plt>

Disassembly of section .plt.got:

0000000000000590 <__cxa_finalize@plt>:
 590:   ff 25 62 0a 20 00       jmpq   *0x200a62(%rip)        # 200ff8 <__cxa_finalize@GLIBC_2.2.5>
 596:   66 90                   xchg   %ax,%ax

Disassembly of section .text:

00000000000005a0 <_start>:
 5a0:   31 ed                   xor    %ebp,%ebp
 5a2:   49 89 d1                mov    %rdx,%r9
 5a5:   5e                      pop    %rsi
 5a6:   48 89 e2                mov    %rsp,%rdx
 5a9:   48 83 e4 f0             and    $0xfffffffffffffff0,%rsp
 5ad:   50                      push   %rax
 5ae:   54                      push   %rsp
 5af:   4c 8d 05 ba 01 00 00    lea    0x1ba(%rip),%r8        # 770 <__libc_csu_fini>
 5b6:   48 8d 0d 43 01 00 00    lea    0x143(%rip),%rcx        # 700 <__libc_csu_init>
 5bd:   48 8d 3d 0c 01 00 00    lea    0x10c(%rip),%rdi        # 6d0 <main>
 5c4:   ff 15 0e 0a 20 00       callq  *0x200a0e(%rip)        # 200fd8 <__libc_start_main@GLIBC_2.2.5>
 5ca:   f4                      hlt    
 5cb:   0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)
 5d0:   48 8d 3d 59 0a 20 00    lea    0x200a59(%rip),%rdi        # 201030 <stdin@@GLIBC_2.2.5>
 5d7:   48 8d 05 59 0a 20 00    lea    0x200a59(%rip),%rax        # 201037 <__TMC_END__+0x7>
 5de:   55                      push   %rbp
 5df:   48 29 f8                sub    %rdi,%rax
 5e2:   48 89 e5                mov    %rsp,%rbp
 5e5:   48 83 f8 0e             cmp    $0xe,%rax
 5e9:   76 15                   jbe    600 <_start+0x60>
 5eb:   48 8b 05 de 09 20 00    mov    0x2009de(%rip),%rax        # 200fd0 <_ITM_deregisterTMCloneTable>
 5f2:   48 85 c0                test   %rax,%rax
 5f5:   74 09                   je     600 <_start+0x60>
 5f7:   5d                      pop    %rbp
 5f8:   ff e0                   jmpq   *%rax
 5fa:   66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)
 600:   5d                      pop    %rbp
 601:   c3                      retq   
 602:   0f 1f 40 00             nopl   0x0(%rax)
 606:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
 60d:   00 00 00 
 610:   48 8d 3d 19 0a 20 00    lea    0x200a19(%rip),%rdi        # 201030 <stdin@@GLIBC_2.2.5>
 617:   48 8d 35 12 0a 20 00    lea    0x200a12(%rip),%rsi        # 201030 <stdin@@GLIBC_2.2.5>
 61e:   55                      push   %rbp
 61f:   48 29 fe                sub    %rdi,%rsi
 622:   48 89 e5                mov    %rsp,%rbp
 625:   48 c1 fe 03             sar    $0x3,%rsi
 629:   48 89 f0                mov    %rsi,%rax
 62c:   48 c1 e8 3f             shr    $0x3f,%rax
 630:   48 01 c6                add    %rax,%rsi
 633:   48 d1 fe                sar    %rsi
 636:   74 18                   je     650 <_start+0xb0>
 638:   48 8b 05 b1 09 20 00    mov    0x2009b1(%rip),%rax        # 200ff0 <_ITM_registerTMCloneTable>
 63f:   48 85 c0                test   %rax,%rax
 642:   74 0c                   je     650 <_start+0xb0>
 644:   5d                      pop    %rbp
 645:   ff e0                   jmpq   *%rax
 647:   66 0f 1f 84 00 00 00    nopw   0x0(%rax,%rax,1)
 64e:   00 00 
 650:   5d                      pop    %rbp
 651:   c3                      retq   
 652:   0f 1f 40 00             nopl   0x0(%rax)
 656:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
 65d:   00 00 00 
 660:   80 3d d1 09 20 00 00    cmpb   $0x0,0x2009d1(%rip)        # 201038 <__TMC_END__+0x8>
 667:   75 27                   jne    690 <_start+0xf0>
 669:   48 83 3d 87 09 20 00    cmpq   $0x0,0x200987(%rip)        # 200ff8 <__cxa_finalize@GLIBC_2.2.5>
 670:   00 
 671:   55                      push   %rbp
 672:   48 89 e5                mov    %rsp,%rbp
 675:   74 0c                   je     683 <_start+0xe3>
 677:   48 8b 3d aa 09 20 00    mov    0x2009aa(%rip),%rdi        # 201028 <__dso_handle>
 67e:   e8 0d ff ff ff          callq  590 <__cxa_finalize@plt>
 683:   e8 48 ff ff ff          callq  5d0 <_start+0x30>
 688:   5d                      pop    %rbp
 689:   c6 05 a8 09 20 00 01    movb   $0x1,0x2009a8(%rip)        # 201038 <__TMC_END__+0x8>
 690:   f3 c3                   repz retq 
 692:   0f 1f 40 00             nopl   0x0(%rax)
 696:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
 69d:   00 00 00 
 6a0:   48 8d 3d 41 07 20 00    lea    0x200741(%rip),%rdi        # 200de8 <__init_array_end+0x8>
 6a7:   48 83 3f 00             cmpq   $0x0,(%rdi)
 6ab:   75 0b                   jne    6b8 <_start+0x118>
 6ad:   e9 5e ff ff ff          jmpq   610 <_start+0x70>
 6b2:   66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)
 6b8:   48 8b 05 29 09 20 00    mov    0x200929(%rip),%rax        # 200fe8 <_Jv_RegisterClasses>
 6bf:   48 85 c0                test   %rax,%rax
 6c2:   74 e9                   je     6ad <_start+0x10d>
 6c4:   55                      push   %rbp
 6c5:   48 89 e5                mov    %rsp,%rbp
 6c8:   ff d0                   callq  *%rax
 6ca:   5d                      pop    %rbp
 6cb:   e9 40 ff ff ff          jmpq   610 <_start+0x70>

00000000000006d0 <main>:
#include <stdio.h>

int main(void)
{
 6d0:   55                      push   %rbp
 6d1:   48 89 e5                mov    %rsp,%rbp
    fprintf(stdin, "Hello world\n");
 6d4:   48 8b 05 55 09 20 00    mov    0x200955(%rip),%rax        # 201030 <stdin@@GLIBC_2.2.5>
 6db:   48 89 c1                mov    %rax,%rcx
 6de:   ba 0c 00 00 00          mov    $0xc,%edx
 6e3:   be 01 00 00 00          mov    $0x1,%esi
 6e8:   48 8d 3d 95 00 00 00    lea    0x95(%rip),%rdi        # 784 <_IO_stdin_used+0x4>
 6ef:   e8 8c fe ff ff          callq  580 <fwrite@plt>
    return 0;
 6f4:   b8 00 00 00 00          mov    $0x0,%eax
}
 6f9:   5d                      pop    %rbp
 6fa:   c3                      retq   
 6fb:   0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

0000000000000700 <__libc_csu_init>:
 700:   41 57                   push   %r15
 702:   41 56                   push   %r14
 704:   41 89 ff                mov    %edi,%r15d
 707:   41 55                   push   %r13
 709:   41 54                   push   %r12
 70b:   4c 8d 25 c6 06 20 00    lea    0x2006c6(%rip),%r12        # 200dd8 <__init_array_start>
 712:   55                      push   %rbp
 713:   48 8d 2d c6 06 20 00    lea    0x2006c6(%rip),%rbp        # 200de0 <__init_array_end>
 71a:   53                      push   %rbx
 71b:   49 89 f6                mov    %rsi,%r14
 71e:   49 89 d5                mov    %rdx,%r13
 721:   4c 29 e5                sub    %r12,%rbp
 724:   48 83 ec 08             sub    $0x8,%rsp
 728:   48 c1 fd 03             sar    $0x3,%rbp
 72c:   e8 1f fe ff ff          callq  550 <_init>
 731:   48 85 ed                test   %rbp,%rbp
 734:   74 20                   je     756 <__libc_csu_init+0x56>
 736:   31 db                   xor    %ebx,%ebx
 738:   0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
 73f:   00 
 740:   4c 89 ea                mov    %r13,%rdx
 743:   4c 89 f6                mov    %r14,%rsi
 746:   44 89 ff                mov    %r15d,%edi
 749:   41 ff 14 dc             callq  *(%r12,%rbx,8)
 74d:   48 83 c3 01             add    $0x1,%rbx
 751:   48 39 dd                cmp    %rbx,%rbp
 754:   75 ea                   jne    740 <__libc_csu_init+0x40>
 756:   48 83 c4 08             add    $0x8,%rsp
 75a:   5b                      pop    %rbx
 75b:   5d                      pop    %rbp
 75c:   41 5c                   pop    %r12
 75e:   41 5d                   pop    %r13
 760:   41 5e                   pop    %r14
 762:   41 5f                   pop    %r15
 764:   c3                      retq   
 765:   90                      nop
 766:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
 76d:   00 00 00 

0000000000000770 <__libc_csu_fini>:
 770:   f3 c3                   repz retq 

Disassembly of section .fini:

0000000000000774 <_fini>:
 774:   48 83 ec 08             sub    $0x8,%rsp
 778:   48 83 c4 08             add    $0x8,%rsp
 77c:   c3                      retq   

main之前有一些函数(程序员的入口点 透视),如_start(从操作系统的角度来看)。 此函数负责初始化main之前所需的内容。到底在哪里 像stdin这样的流被初始化,我不知道,我找不到任何可靠的 有关此事的消息来源。

在这个answer中,有一个很好的链接可以更详细地解释这一点: How the heck do we get to main()?

  

来自维基百科 - “Unix的一些突破性进展是抽象设备,它已被删除   需要一个程序来了解或关心它与之通信的设备类型“   “在Unix之前的大多数操作系统中,程序必须明确连接到   适当的输入和输出设备......强制程序员使用较旧的操作系统   记录结构和频繁的非正交数据语义和设备控制。“

我认为文章试图说的是,在类Unix系统中,作为程序员你 不必担心通信背后的设备,因为在Unix中 “everything is a file”。你可以做到

fopen("/some/file.txt", "r");
fopen("/dev/sda1", "r"); // if you have reading access
fopen("/dev/some_device", "r");

你的程序不需要知道/dev/sda1是a的第一个分区 SCSI总线中的硬盘驱动器,或/dev/some_device实际上是PCI设备。

似乎在Unix之前,作为程序员,你必须知道哪种类型 你想和之交谈的设备。但我太年轻了,无法与这个时代联系,我不是 甚至出生,所以我可能完全错了。

  

也来自维基百科 - “另一个Unix突破是自动关联输入和输出   到终端键盘和终端显示,默认情况下 - 程序   (和程序员)完全没有为a建立输入和输出   典型的输入 - 输出 - 输出程序(除非它选择了不同的范例)。   相比之下,以前的操作系统通常需要一些通常很复杂的工作   控制语言建立联系,或相当的负担必须   由该计划精心策划。“

这就是我在答案开头时所说的。

  

最后,有这些问题的人应该通过什么资源来进一步理解他们的流?

我总是非常重视过去的技术,这当然不是坏事 想知道过去的工作方式。如果你真的感兴趣的话 场景,我认为LiS: Linux STREAMS文章非常有趣。

从程序员的角度来看,您需要知道的是stdinstdout, 在您的计划开始时为您提供stderr 您必须使用stdio.h中的函数来访问它们。