• 软件测试技术
  • 软件测试博客
  • 软件测试视频
  • 开源软件测试技术
  • 软件测试论坛
  • 软件测试沙龙
  • 软件测试资料下载
  • 软件测试杂志
  • 软件测试人才招聘
    暂时没有公告

字号: | 推荐给好友 上一篇 | 下一篇

操作系统的实现细节(2)

发布: 2007-7-04 12:06 | 作者: admin | 来源:  网友评论 | 查看: 17次 | 进入软件测试论坛讨论

领测软件测试网 在第一篇文章里面详细说了一下系统启动和文件系统的一些差别,这篇文章我想理清一下思路,想象最初的引导程序获得了系统地引导权以后,后面所应该做的事情?

现在做个假设,如果自己用c语言写一段hello world程序,用armlinux-gcc编译器编译好,然后用jtag烧写到板子得flash当中,程序是否可以运行?答案是相当否定的。因为这个时候,没有对底层的硬件做任何的初始化,可以通过汇编,直接对串口进行操作,但是对于gcc的printf,毕竟也是一个高级的包装函数,现在根据gcc的源代码顺藤摸瓜,看看具体是怎么实现的?

//printf.c

int
printf (const char *string, ...)
{
  va_list ap;
  int r;
#ifdef __OPTIMIZE__
  if (inside_main)
    abort();
#endif
  va_start (ap, string);
  r = vprintf (string, ap);
  va_end (ap);
  return r;
}

//vprintf.c

nt
vprintf (format, ap)
     const char *format;
     va_list ap;
{
  return vfprintf (stdout, format, ap);
}
//FILE *stdout

typedef struct _iobuf
{
 char* _ptr;
 int _cnt;
 char* _base;
 int _flag;
 int _file;
 int _charbuf;
 int _bufsiz;
 char* _tmpfname;
} FILE;

//vfprintf.c

int
vfprintf (stream, format, ap)
  FILE * stream;
  const char * format;
  va_list ap;
{
  return _doprnt (format, ap, stream);
}

//_doprnt.c


int
_doprnt (format, ap, stream)
  const char * format;
  va_list ap;
  FILE * stream;
{
  const char * ptr = format;
  char specifier[128];
  int total_printed = 0;
 
  while (*ptr != '')
    {
      if (*ptr != '%') /* While we have regular characters, print them.  */
 PRINT_CHAR(*ptr);
      else /* We got a format specifier! */
 {
   char * sptr = specifier;
   int wide_width = 0, short_width = 0;
  
   *sptr++ = *ptr++; /* Copy the % and move forward.  */

   while (strchr ("-+ #0", *ptr)) /* Move past flags.  */
     *sptr++ = *ptr++;

   if (*ptr == '*')
     COPY_VA_INT;
   else
     while (ISDIGIT(*ptr)) /* Handle explicit numeric value.  */
       *sptr++ = *ptr++;
  
   if (*ptr == '.')
     {
       *sptr++ = *ptr++; /* Copy and go past the period.  */
       if (*ptr == '*')
  COPY_VA_INT;
       else
  while (ISDIGIT(*ptr)) /* Handle explicit numeric value.  */
    *sptr++ = *ptr++;
     }
   while (strchr ("hlL", *ptr))
     {
       switch (*ptr)
  {
  case 'h':
    short_width = 1;
    break;
  case 'l':
    wide_width++;
    break;
  case 'L':
    wide_width = 2;
    break;
  default:
    abort();
  }
       *sptr++ = *ptr++;
     }

   switch (*ptr)
     {
     case 'd':
     case 'i':
     case 'o':
     case 'u':
     case 'x':
     case 'X':
     case 'c':
       {
  /* Short values are promoted to int, so just copy it
                   as an int and trust the C library printf to cast it
                   to the right width.  */
  if (short_width)
    PRINT_TYPE(int);
  else
    {
      switch (wide_width)
        {
        case 0:
   PRINT_TYPE(int);
   break;
        case 1:
   PRINT_TYPE(long);
   break;
        case 2:
        default:
#if defined(__GNUC__) || defined(HAVE_LONG_LONG)
   PRINT_TYPE(long long);
#else
   PRINT_TYPE(long); /* Fake it and hope for the best.  */
#endif
   break;
        } /* End of switch (wide_width) */
    } /* End of else statement */
       } /* End of integer case */
       break;
     case 'f':
     case 'e':
     case 'E':
     case 'g':
     case 'G':
       {
  if (wide_width == 0)
    PRINT_TYPE(double);
  else
    {
#if defined(__GNUC__) || defined(HAVE_LONG_DOUBLE)
      PRINT_TYPE(long double);
#else
      PRINT_TYPE(double); /* Fake it and hope for the best.  */
#endif
    }
       }
       break;
     case 's':
       PRINT_TYPE(char *);
       break;
     case 'p':
       PRINT_TYPE(void *);
       break;
     case '%':
       PRINT_CHAR('%');
       break;
     default:
       abort();
     } /* End of switch (*ptr) */
 } /* End of else statement */

}

return total_printed;
}

#define PRINT_CHAR(CHAR) \
  do { \
  putc(CHAR, stream); \
  ptr++; \
  total_printed++; \
  continue; \
     } while (0)

//System.h

#  define putc(C, Stream) putc_unlocked (C, Stream)

//2005-06-22

刚才下载了2.95的gcc,发现了可以继续探索下去

//putc_u.h

int
putc_unlocked (c, fp)
     int c;
     _IO_FILE *fp;
{
  CHECK_FILE (fp, EOF);
  return _IO_putc_unlocked (c, fp);
}

//libio.h
struct _IO_FILE {
  int _flags;  /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags

  /* The following pointers correspond to the C++ streambuf protocol. */
  /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
  char* _IO_read_ptr; /* Current read pointer */
  char* _IO_read_end; /* End of get area. */
  char* _IO_read_base; /* Start of putback+get area. */
  char* _IO_write_base; /* Start of put area. */
  char* _IO_write_ptr; /* Current put pointer. */
  char* _IO_write_end; /* End of put area. */
  char* _IO_buf_base; /* Start of reserve area. */
  char* _IO_buf_end; /* End of reserve area. */
  /* The following fields are used to support backing up and undo. */
  char *_IO_save_base; /* Pointer to start of non-current get area. */
  char *_IO_backup_base;  /* Pointer to first valid character of backup area */
  char *_IO_save_end; /* Pointer to end of non-current get area. */

  struct _IO_marker *_markers;

  struct _IO_FILE *_chain;

  int _fileno;
  int _blksize;
#ifdef _G_IO_IO_FILE_VERSION
  _IO_off_t _old_offset;
#else
  _IO_off_t _offset;
#endif

#define __HAVE_COLUMN /* temporary */
  /* 1+column number of pbase(); 0 is unknown. */
  unsigned short _cur_column;
  char _unused;
  char _shortbuf[1];

  /*  char* _save_gptr;  char* _save_egptr; */

#ifdef _IO_LOCK_T
  _IO_LOCK_T _lock;
#endif
#if defined(_G_IO_IO_FILE_VERSION) && _G_IO_IO_FILE_VERSION == 0x20001
  _IO_off64_t _offset;
  int _unused2[16]; /* Make sure we don't get into trouble again.  */
#endif
};


#define _IO_putc_unlocked(_ch, _fp) \
   (((_fp)->_IO_write_ptr >= (_fp)->_IO_write_end) \
    ? __overflow (_fp, (unsigned char) (_ch)) \
    : (unsigned char) (*(_fp)->_IO_write_ptr++ = (_ch)))
继续...

int
__overflow (f, ch)
     _IO_FILE *f;
     int ch;
{
  return _IO_OVERFLOW (f, ch);
}

//libiop.h

/* The 'overflow' hook flushes the buffer.
   The second argument is a character, or EOF.
   It matches the streambuf::overflow virtual function. */
typedef int (*_IO_overflow_t) __PMT ((_IO_FILE *, int));
#define _IO_OVERFLOW(FP, CH) JUMP1 (__overflow, FP, CH)

//go on...

# define JUMP1(FUNC, THIS, X1) _IO_JUMPS(THIS)->FUNC (THIS, X1)

#define _IO_JUMPS(THIS) ((struct _IO_FILE_plus *) (THIS))->vtable

struct _IO_FILE_plus
{
  _IO_FILE file;
  const struct _IO_jump_t *vtable;
};

struct _IO_jump_t
{
    JUMP_FIELD(_G_size_t, __dummy);
#ifdef _G_USING_THUNKS
    JUMP_FIELD(_G_size_t, __dummy2);
#endif
    JUMP_FIELD(_IO_finish_t, __finish);
    JUMP_FIELD(_IO_overflow_t, __overflow);
    JUMP_FIELD(_IO_underflow_t, __underflow);
    JUMP_FIELD(_IO_underflow_t, __uflow);
    JUMP_FIELD(_IO_pbackfail_t, __pbackfail);
    /* showmany */
    JUMP_FIELD(_IO_xsputn_t, __xsputn);
    JUMP_FIELD(_IO_xsgetn_t, __xsgetn);
    JUMP_FIELD(_IO_seekoff_t, __seekoff);
    JUMP_FIELD(_IO_seekpos_t, __seekpos);
    JUMP_FIELD(_IO_setbuf_t, __setbuf);
    JUMP_FIELD(_IO_sync_t, __sync);
    JUMP_FIELD(_IO_doallocate_t, __doallocate);
    JUMP_FIELD(_IO_read_t, __read);
    JUMP_FIELD(_IO_write_t, __write);
    JUMP_FIELD(_IO_seek_t, __seek);
    JUMP_FIELD(_IO_close_t, __close);
    JUMP_FIELD(_IO_stat_t, __stat);
#if _G_IO_IO_FILE_VERSION == 0x20001
    JUMP_FIELD(_IO_showmanyc_t, __showmanyc);
    JUMP_FIELD(_IO_imbue_t, __imbue);
#endif
#if 0
    get_column;
    set_column;
#endif
};

哈,终于找到了最终的函数_IO_seek_t ,__write,根据此处的经验来看,应该为操作系统实现的。

费了这么大一半天,只是想说明,gcc编译出来的东西,其依赖于操作系统的实现,也即是说,gcc和操作系统是相辅相成的,操作系统负责提供一些最底层的基本的函数,而gcc则把这些东西包装起来。

具体细节,在编操作系统的时候,例如定制自己的mystdio.h,里面实现__swbuf函数,然后就可以调用printf啦

不过有点迷惑,是如何商量好__swbuf函数的?莫非还能继续分解下去?还请通晓之人指教以下~

其实说到最后,无论elf还是exe格式,说到底都是2进制文件,它们的差别,就在于操作系统的实现差别,操作系统装入这些可执行文件的text段啊,动态连接库等等的不同,导致了各个文件只能在其自己的系统上运行,而linux下面的wine软件,正是看到了这点,把windows对于exe文件的前期配置按照linux配置完毕,然后么,跳转到可执行代码段,剩下的就是机器自己的事情了。

为完待续。。。

下回将分析一下,操作系统是如何运行一个文件的?需要做哪些前期工作?可执行文件里面包含了什么秘密?

延伸阅读

文章来源于领测软件测试网 https://www.ltesting.net/


关于领测软件测试网 | 领测软件测试网合作伙伴 | 广告服务 | 投稿指南 | 联系我们 | 网站地图 | 友情链接
版权所有(C) 2003-2010 TestAge(领测软件测试网)|领测国际科技(北京)有限公司|软件测试工程师培训网 All Rights Reserved
北京市海淀区中关村南大街9号北京理工科技大厦1402室 京ICP备10010545号-5
技术支持和业务联系:info@testage.com.cn 电话:010-51297073

软件测试 | 领测国际ISTQBISTQB官网TMMiTMMi认证国际软件测试工程师认证领测软件测试网