uClibc和Glibc区别

uClibc and Glibc are not the same -- there are a number of differences which
may or may not cause you problems.  This document attempts to list these
differences and, when completed, will contain a full list of all relevant
differences.
1) uClibc is smaller than glibc.  We attempt to maintain a glibc compatible
interface, allowing applications that compile with glibc to easily compile with
uClibc.  However, we do not include _everything_ that glibc includes, and
therefore some applications may not compile.  If this happens to you, please
report the failure to the uclibc mailing list, with detailed error messages.
2) uClibc is much more configurable then glibc.  This means that a developer
may have compiled uClibc in such a way that significant amounts of
functionality have been omitted.
3) uClibc does not even attempt to ensure binary compatibility across releases.
When a new version of uClibc is released, you may or may not need to recompile
all your binaries.
4) malloc(0) in glibc returns a valid pointer to something(!?!?) while in
uClibc calling malloc(0) returns a NULL.  The behavior of malloc(0) is listed
as implementation-defined by SuSv3, so both libraries are equally correct.
This difference also applies to realloc(NULL, 0).  I personally feel glibc's
behavior is not particularly safe.  To enable glibc behavior, one has to
explicitly enable the MALLOC_GLIBC_COMPAT option.
4.1) glibc's malloc() implementation has behavior that is tunable via the
MALLOC_CHECK_ environment variable.  This is primarily used to provide extra
malloc debugging features.  These extended malloc debugging features are not
available within uClibc.  There are many good malloc debugging libraries
available for Linux (dmalloc, electric fence, valgrind, etc) that work much
better than the glibc extended malloc debugging.  So our omitting this
functionality from uClibc is not a great loss.
5) uClibc does not provide a database library (libdb).
6) uClibc does not support NSS (/lib/libnss_*), which allows glibc to easily
support various methods of authentication and DNS resolution.  uClibc only
supports flat password files and shadow password files for storing
authentication information.  If you need something more complex than this,
you can compile and install pam.
7) uClibc's libresolv is only a stub.  Some, but not all of the functionality
provided by glibc's libresolv is provided internal to uClibc.  Other functions
are not at all implemented.
8) libnsl provides support for Network Information Service (NIS) which was
originally called "Yellow Pages" or "YP", which is an extension of RPC invented
by Sun to share Unix password files over the network.  I personally think NIS
is an evil abomination and should not be used.  These days, using ldap is much
more effective mechanism for doing the same thing.  uClibc provides a stub
libnsl, but has no actual support for Network Information Service (NIS).
We therefore, also do not provide any of the headers files provided by glibc
under /usr/include/rpcsvc.
9) uClibc's locale support is not 100% complete yet.  We are working on it.
10) uClibc's math library only supports long double as inlines, and even
then the long double support is quite limited.  Also, very few of the
float math functions are implemented.  Stick with double and you should
be just fine.
11) uClibc's libcrypt does not support the reentrant crypt_r, setkey_r and
encrypt_r, since these are not required by SuSv3.
12) uClibc directly uses kernel types to define most opaque data types.
13) uClibc directly uses the linux kernel's arch specific 'stuct stat'.
14) uClibc's librt library currently lacks all aio routines, all clock
    routines, and all shm routines (only the timer routines and the mq
    routines are implemented).
******************************  Manuel's Notes  ******************************
Some general comments...
The intended target for all my uClibc code is ANSI/ISO C99 and SUSv3
compliance.  While some glibc extensions are present, many will eventually
be configurable.  Also, even when present, the glibc-like extensions may
differ slightly or be more restrictive than the native glibc counterparts.
They are primarily meant to be porting _aides_ and not necessarily
drop-in replacements.
Now for some details...
time functions
--------------
1) Leap seconds are not supported.
2) /etc/timezone and the whole zoneinfo directory tree are not supported.
   To set the timezone, set the TZ environment variable as specified in
   
http://www.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap08.html
   or you may also create an /etc/TZ file of a single line, ending with a
   newline, containing the TZ setting.  For example
   echo CST6CDT > /etc/TZ
3) Currently, locale specific eras and alternate digits are not supported.
   They are on my TODO list.
wide char support
-----------------
1) The only multibyte encoding currently supported is UTF-8.  The various
   ISO-8859-* encodings are (optionally) supported.  The internal
   representation of wchar's is assumed to be 31 bit unicode values in
   native endian representation.  Also, the underlying char encoding is
   assumed to match ASCII in the range 0-0x7f.
2) In the next iteration of locale support, I plan to add support for
   (at least some) other multibyte encodings.
locale support
--------------
1) The target for support is SUSv3 locale functionality.  While nl_langinfo
   has been extended, similar to glibc, it only returns values for related
   locale entries.
2) Currently, all SUSv3 libc locale functionality should be implemented
   except for wcsftime and collating item support in regex.
stdio
-----
1) Conversion of large magnitude floating-point values by printf suffers a loss
   of precision due to the algorithm used.
2) uClibc's printf is much stricter than glibcs, especially regarding positional
   args.  The entire format string is parsed first and an error is returned if
   a problem is detected.  In locales other than C, the format string is checked
   to be a valid multibyte sequence as well.  Also, currently at most 10 positional
   args are allowed (although this is configurable).
3) BUFSIZ is configurable, but no attempt is made at automatic tuning of internal
   buffer sizes for stdio streams.  In fact, the stdio code in general sacrifices
   sophistication/performace for minimal size.
4) uClibc allows glibc-like custom printf functions.  However, while not
   currently checked, the specifier must be


原文链接:
http://www.ucdot.org/article.pl?sid=02/08/21/1124218&mode=thread
What is the difference between uC-libc and uClibc There are two libc libraries commonly used with uClinux. uC-libc and uClibc. They are quite different despite their similar names. Here is a quick overview of how they are different.
uC-libc is the original library for uClinux. It was based on sources from the Linux-8086 C library which was part of the
ELKs
project with m68000 support added by Jeff Dionne and Kenneth Albanowski. It is a fairly complete libc implementation, however, some of the API's are a little non-standard and quite a few common libc routines are not present. Currently it has stable support for m68000, ColdFire and ARM (Non-MMU) architectures. It was primary design goal is to be small and light weight. It does try to conform to any standards, although its API tries to be compatible with most libcs, it is not always exactly the same.
uClibc is a derivative of uC-libc designed to fix the problems with uC-libc. It makes all the API's standard (correct types, args, etc), fills in many of the missing routines, and has been ported to a lot of architectures. In general it tries to provide glibc compatibility so that porting applications to the smaller uClibc is quite easy. It can be used on standard VM Linux and uClinux. To make it even more compact it can also be compiled as a shared library on most platforms with MMU support
Erik Andersen
has been the driving force behind uClibc and has done a great job. uClibc supports a large array of processors: m68000, Coldfire, ARM, MIPS, v850, x86, i960, Sparc, SuperH, Alpha, PowerPC and Hitachi 8. uClibc is much easier to adapt to a new architecture and its ever growing platform support is testimony to this.
The uClinux distribution provides an environment that can compile using either uC-libc or uClibc depending on your needs. For m68000 and Coldfire platforms it is generally better to chose uC-libc as it supports shared libraries and is the most commonly used libc for these CPUs. uClibc also works quite well with almost all platforms supported by the distribution. Which libc you choose to use will be decided by your requirements.


µ C l i b c
About



  • About


  • Latest News
Documentation


  • FAQ
Obtain


  • Download


  • Toolchains


  • Products
Development


  • Browse Source


  • Mailing Lists


  • Developing


  • Bug Tracking
Links


  • Other libcs
    Related Sites

  • uClibc++


  • BusyBox


  • buildroot


  • Scratchbox


  • OpenEmbedded


  • uCdot


  • LinuxDevices


  • Slashdot


  • Freshmeat


  • Linux Today


  • Linux Weekly News


  • Linux HOWTOs


  • 28 October 2008, uClibc 0.9.30-rc3 Released
    0.9.30-rc3 is out of the door. Please test this release candidate to shake out possible regressions before the final 0.9.30.
    Head to the
    downloads page
    to pick up the
    0.9.30-rc3 release
    .
  • 15 October 2008, uClibc 0.9.30-rc2 Released
    After quite some time of bugfixing and general improvement all over the place we have a 0.9.30-rc2. Please test this release candidate to shake out possible regressions before the final 0.9.30. Target for the release is end of october.
    Head to the
    downloads page
    to pick up the
    0.9.30-rc2 release
    .
  • 22 August 2008, Status
    Quite some fixes went into
    trunk
    during the last couple of months, umong them fixes for arm, mips, sh, i386, x86_64 and some bits for cris, powerpc and others. Several architecture independent tweaks and improvements found their way into trunk, too.
    A couple of new configuration options were added to allow for even more fine-grained selection of the desired exported functionality. These new options are in the "Advanced Library Settings" menu and include

    • Realtime-related family of SUSv functions
    • Advanced realtime-related family of SUSv functions
    • epoll
    • Extended Attributes
    • a handful of options to turn off compatibility APIs and deprecated functions

    Furthermore it is now possible to build uClibc without networking support (for certain configurations):

    • No network
    • Socket
    • IPv4
    • IPv6

    An allnoconfig setup with shared library support is about 30% smaller than it was previously.
    Further work will be needed to completely decouple advanced RT from RT as well as building a purely IPv6 capable library without any IPv4 support.
  • 6 May 2007, uClibc 0.9.29 Released
    Smacked down a few more bugs in the malloc implementations for no-MMU and finally got this one out. Again, this one should be binary compatible with the 0.9.28 series, but no one has explicitly tested this, so let us know!
    Head to the
    downloads page
    to pick up the
    0.9.29 release
    .
  • 17 April 2007, uClibc 0.9.29_rc1 Released
    After the long goodbye, we have 0.9.29_rc1. Post your regressions and we'll pound out as many before 0.9.29. Target for this is end of the week. After that, we'll try to continue with the release-early-release-often schedule. This one should be binary compatible with the 0.9.28 series, but no one has explicitly tested this, so let us know!
    Head to the
    downloads page
    to pick up the
    0.9.29_rc1 release
    .
  • 28 February 2007, uClibc 0.9.28.3 Released
    We're aiming for a new release-early-release-often record or something with the release of uClibc-0.9.28.3, which fixes a few more problems that turned up after last week's 0.9.28.2 release -- in particular a problem with weak threading symbols. As with last week's release, this is intended as a drop-in replacement for the long-term stable uClibc 0.9.28 release series.
    Head to the
    downloads page
    to pick up the
    0.9.28.3 release
    .
  • Old News
    Click here to read
    older news
    .

GNU C Library
Main page
Bugs
Manual
Resources

Table of Contents


  • Overview


  • Current Status


  • Availability


  • Bugs


  • Resources


  • People

Overview
Any Unix-like operating system needs a C library: the library which defines the ``system calls'' and other basic facilities such as open, malloc, printf, exit...
The GNU C library is used as the C library in the GNU system and most systems with the Linux kernel.
History
The history of Unix and various standards determine much of the interface of the C library. In general the GNU C library supports the ISO C and POSIX standards. We also try to support the features of popular Unix variants (including BSD and System V) when those do not conflict with the standards. Different compatibility modes (selectable when you compile an application) allow the peaceful coexistence of compatibility support for different varieties of Unix.
Project Goals
The GNU C library is primarily designed to be a portable and high performance C library.
It follows all relevant standards (ISO C 99, POSIX.1c, POSIX.1j, POSIX.1d, Unix98, Single Unix Specification). It is also internationalized and has one of the most complete internationalization interfaces known.
Contributing
Today the GNU C library is almost complete: nearly all known and useful functions from any other C library are available. However, there is still room for improvement. If you would like to add or improve features in the GNU C library, please look through at the latest
PROJECTS
file distributed with the glibc source, and coordinate your work with the maintainers at

.
Note that most large contributions to the code base will require authors to file copyright papers with the FSF. Please contact the maintainers with any queries.
Standards Conformance
glibc distributes a
CONFORMANCE
report detailing adherence to various standards. This list also shows where GNU libc needs to be improved.
Manual
The GNU C library manual is incomplete. It would be very helpful if you could spend a bit of your time on writing the missing parts. Please coordinate your work with the maintainers

.
Porting
For more information on the process of porting see
Porting the C Library
in the glibc manual. The status of ports and their sub-maintainers is currently documented on the
ports
page. If you are interested in porting GNU libc to additional system types, please contact the maintainers

before beginning your port.
Current Status
The current version is 2.8.
See the
NEWS
file for more information.
There is a
FAQ
which you should read first.
Availability
Releases are available by CVS branch checkout only. For example, to download the 2.8 release, checkout the CVS libc module branch glibc-2_8-branch, and similarly for all required add-ons including ports.
Archives of the old releases are available at
http://ftp.gnu.org/gnu/glibc/
and its mirrors.
For more information on porting see
Porting the GNU C Library
.
Bugs
See
this page
for information on reporting bugs in the GNU C Library.
Resources
The canonical source for information about the GNU C Library the reference manual available at
" target=_blank>http://www.gnu.org/software/libc/manual/>
;
Also see
this page
for some resources relevant to the GNU C Library.
People
The GNU C library was originally written primarily by Roland McGrath

when he worked for the FSF. In 2001 The GNU C Library Steering Committee

, was formed and currently consists of Mark Brown, Paul Eggert, Andreas Jaeger, Jakub Jelinek, Roland McGrath and Andreas Schwab. Ulrich Drepper is currently the foremost contributor and has overall responsibility for maintenance and development.
Many others have contributed in large amounts as documented in the glibc
Contributors
.
Please send FSF & GNU inquiries & questions to
[email protected]
. There are also
other ways to contact
the FSF.
Please send comments on these web pages to
[email=webmasters
www.gnu.org
]webmasterswww.gnu.org[/email]
. Send other questions to
[email protected]
.
Copyright © 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.
Updated: $Date: 2008/10/23 16:21:23 $

uClibc 中的 malloc 和 free
作者:
Hily
原始链接:
http://hily.me/blog/2007/06/uclibc-malloc-free/
版权声明:可以转载,转载时务必以超链接形式标题文章
原始出处

作者信息

版权声明

  uClibc 是一个小型的 C 库,应用于嵌入式 Linux 系统开发。它基本实现了 glibc 的功能,几乎所有 glibc 支持的应用程序都能在 uClibc 上运行,这使得应用程序的移植变得相当简单,只需要使用 uClibc 库重新编译源代码就可以了。目前 uClibc 主要运行在不带 MMU 的平台下,支持 alpha, ARM, i386, i960, h8300, m68k, mips/mipsel, PowerPC, SH, SPARC 等等。
  在国内,Linux 的小型应用一般采用 ARM7 作为处理器(见得较多的是Samsung S3C44B0X),加上开源的 uClinux 作为操作系统,构成一个价格上相对较低的嵌入式开发平台。
  在 uClinux 上最经常使用的 C 库,便是 uClibc,本篇主要是对 uClibc 中的 malloc 和 free 做简要分析,希望能起到一个抛砖引玉的作用。目前我使用的开发平台为 S3C44B0X + uClinux (Kernel Version 2.4.20),uClibc 的版本为 0.9.19,版本虽然旧了些,但不影响理解 malloc 的工作机制,而且可能更有利(通常版本越高,代码越复杂)。
  顺便在此附上该版本 malloc 部分的代码,它位于 uClibc/libc/stdlib/ 目录下。
点击下载文件
Hily Jiang
Email&Gtalk: hilyjiang at Gmail
Blog:
http://hily.me/blog/
一、头文件中的声明
malloc 和 free 在头文件 stdlib.h 中声明:
/* Allocate SIZE bytes of memory.  */
extern void *malloc (size_t __size) __THROW __attribute_malloc__;
/* Free a block allocated by `malloc', `realloc' or `calloc'.  */
extern void free (void *__ptr) __THROW;
malloc 返回一个指定大小为 __size 的指针。
free 释放指针 __ptr 指向的内存空间。
二、基本机制
stdlib 中的 malloc 模块维护了一个空闲区域的链表,这个链表可以说是这个模块最为核心的部分。
当调用 malloc 申请空间时,先检查该链表中是否有满足条件的空闲区域节点,如果没有,则向内核申请内存空间,放入这个链表中,然后再重新在链表中查找一次满足条件的空闲区域节点。
当调用 free 释放空间时,把释放的空间放入空闲区域中。和 malloc 相对应地,如果空闲的空间大于某个阈值时,调用 free 时会把不需要的空间再还给内核,以节约内存。
三、两个重要的结构
前面说到这个模块中最核心的空闲区域链表,它的节点结构为(heap.h中):
struct heap_free_area
{
    size_t size;
    struct heap_free_area *next, *prev;
};
size 表示该空闲区域的大小,这个空闲区域的实际地址并没有用指针详细地指明,因为它就位于当前 heap_free_area 节点的前面,如下图所示:
+-------------------------------+--------------------+
|                               |   heap_free_area   |
+-------------------------------+--------------------+
\___________ 空闲空间 ___________/\___ 空闲空间信息 ___/
从图上我们可以看出,实际可用的空闲空间大小为 size - sizeof(struct heap_free_area)。
指针 next, prev 分别指向下一个和上一个空间区域,所有的空闲区域就是通过许许多多这样的节点链起来的,很显然,这样组成的是一个双向链表。
双向链表的头节点由另外一个结构 heap 索引,heap 的定义为(heap.h中):
struct heap
{
  /* A list of memory in the heap available for allocation.  */
  struct heap_free_area *free_areas;
#ifdef HEAP_USE_LOCKING
  /* A lock that can be used by callers to control access to the heap.
     The heap code _does not_ use this lock, it's merely here for the
     convenience of users!  */
  pthread_mutex_t lock;
#endif
};
heap 结构中只有两个成员,free_areas 指向空间区域链表头节点,lock 在多线程环境中作线程锁使用。
四、模块初始化
malloc 模块的初始化,其实就是对以上两个结构的初始化,在 malloc.c 中进行:
/* The malloc heap.  We provide a bit of initial static space so that
   programs can do a little mallocing without mmaping in more space.  */
HEAP_DECLARE_STATIC_FREE_AREA (initial_fa, 256);
struct heap __malloc_heap = HEAP_INIT_WITH_FA (initial_fa);
宏 HEAP_DECLARE_STATIC_FREE_AREA 在 heap.h 中定义:
#define HEAP_DECLARE_STATIC_FREE_AREA(name, size)            \
  static struct                                \
  {                                    \
    char space[(size) - sizeof (struct heap_free_area)];        \
    struct heap_free_area _fa;                        \
  } name = { "", { (size), 0, 0 } }
HEAP_DECLARE_STATIC_FREE_AREA 在这里初始化了一个大小为 256 字节的静态空闲区域。
接下来创建一个 heap,它的 free_areas 成员指向上面这个刚初始化的空间中的 _fa,同时初始化线程锁:
# define HEAP_INIT_WITH_FA(fa)    { &fa._fa, PTHREAD_MUTEX_INITIALIZER }
至此初始化完毕,生成了一个 heap 结构,它的 free_areas 成员指向一个静态空间区域。
五、malloc 解读
malloc 函数在 malloc.c 中定义,它实际上是调用 malloc_from_heap 从空闲区域中申请空间。
为减短篇幅,下面采用源代码注释的方法进行解读,同样删除了一些对于理解工作原理不太重要的代码:
static void *
malloc_from_heap (size_t size, struct heap *heap)
{
  void *mem;
  /* 一个 malloc 块的结构如下:
     +--------+---------+-------------------+
     | SIZE   |(unused) | allocation  ...   |
     +--------+---------+-------------------+
     ^ BASE             ^ ADDR
     ^ ADDR - MALLOC_ALIGN
     申请成功后返回的地址是 ADDR
     SIZE 表示块的大小,包括前面的那部分,也就是 MALLOC_HEADER_SIZE
  */
  size += MALLOC_HEADER_SIZE;
  /* 申请线程锁,避免其它线程操作 heap 引起冲突 */
  __heap_lock (heap);
  /* 从 heap 中申请大小为 size 的空间 */
  mem = __heap_alloc (heap, &size);
  /* 释放线程锁 */
  __heap_unlock (heap);
  if (! mem)
    /* 如果空间申请失败,则从系统中申请空间放入 heap 后再重新申请  */
    {
      /* 从系统申请空间时,最小的单元为 MALLOC_HEAP_EXTEND_SIZE,大于 MALLOC_HEAP_EXTEND_SIZE 时,
        则根据需要的空间大小向上申请 MALLOC_HEAP_EXTEND_SIZE 的整数倍大小的空间 */
      void *block;
      size_t block_size
    = (size
malloc_from_heap 中调用了两个重要的函数,以下分别作解读。
__heap_alloc函数,位于 heap_alloc.c,这个函数的作用就是从空闲区域链表中找到满足条件的节点,同时它会修改参数中的 size,返回实际分配的空间大小:
void *
__heap_alloc (struct heap *heap, size_t *size)
{
  struct heap_free_area *fa;
  size_t _size = *size;
  void *mem = 0;
  /* 根据 HEAP_GRANULARITY 大小向上取整,在 heap.h 中定义 */
  _size = HEAP_ADJUST_SIZE (_size);
  /* 在空闲区域链表中查找大小大于等于 _SIZE 的节点  */
  for (fa = heap->free_areas; fa; fa = fa->next)
    if (fa->size >= _size)
      {
    /* 找到满足条件的节点 */
    mem = HEAP_FREE_AREA_START (fa);
    *size = __heap_free_area_alloc (heap, fa, _size);
    break;
      }
  return mem;
}
在链表中如果找到满足条件的节点,则通过 __heap_free_area_alloc 分配空间(heap.h中):
extern inline size_t
__heap_free_area_alloc (struct heap *heap,
            struct heap_free_area *fa, size_t size)
{
  size_t fa_size = fa->size;
  if (fa_size size __________/
       分配后:
            ___ 已分配 __     __ 空闲空间 __   __ 空闲空间信息 __
    /             \ /              \ /                  \
    +-------------------------------+--------------------+
    |              |                |   heap_free_area   |
    +-------------------------------+--------------------+
    \____ size ___/ \__ fa->size __/
    */
    fa->size = fa_size - size;
  return size;
}
如果第一次申请空间不成功,就会向系统申请空间,通过 __heap_free 加入到 heap 的空闲区域链表中。
__heap_free 在 heap_free.c 中被定义,它将指定的内存区域加入链表:
struct heap_free_area *
__heap_free (struct heap *heap, void *mem, size_t size)
{
  struct heap_free_area *fa, *prev_fa;
  void *end = (char *)mem + size;
  /* 空闲区域链表是按照地址从小到大排列的,这个循环是为了找到 mem 应该插入的位置 */
  for (prev_fa = 0, fa = heap->free_areas; fa; prev_fa = fa, fa = fa->next)
    if (HEAP_FREE_AREA_END (fa) >= mem)
      break;
  if (fa && HEAP_FREE_AREA_START (fa) size + size;
      if (HEAP_FREE_AREA_START (fa) == end)
        /* mem 在 fa 之前
       如果 fa 和 mem 是连续的,那么将 mem 空间并入 fa 节点管理
       +---------------+--------------+---------------+
       |       |prev_fa|      mem     |       |   fa  |
       +---------------+--------------+---------------+
                          ^______________________________^
           prev_fa 与 fa 的链接关系不变,只要更改 fa 中的 size 就可以了
    */
    {
      /* 如果 fa 前一个节点和 mem 是连续的,那么将 fa 前一个节点的空间
         也并入 fa 节点管理
       +---------------+---------------+--------------+---------------+
       |       |pre2_fa|       |prev_fa|      mem     |       |   fa  |
       +---------------+---------------+--------------+---------------+
                          ^______________________________________________^
        将 prev_fa 从链表中移出,同时修改 fa 中的 size
          */
      if (prev_fa && mem == HEAP_FREE_AREA_END (prev_fa))
        {
          fa_size += prev_fa->size;
          __heap_link_free_area_after (heap, fa, prev_fa->prev);
        }
    }
      else
    /* mem 在 fa 之后 */
    {
      struct heap_free_area *next_fa = fa->next;
      /* 如果 mem 与 next_fa 是连续的,将 mem 并入 next_fa 节点管理
        +---------------+--------------+--------------+---------------+
       |       |prev_fa|      |   fa  |      mem     |       |next_fa|
       +---------------+--------------+--------------+---------------+
                          ^_____________________________________________^
       将 fa 从链表中移出,同时修改 next_fa 中的 size
      */
      if (next_fa && end == HEAP_FREE_AREA_START (next_fa))
        {
          fa_size += next_fa->size;
          __heap_link_free_area_after (heap, next_fa, prev_fa);
          fa = next_fa;
        }
      else
        {
        /* 如果 mem 与 next_fa 不连续,将 fa 结点移到 mem 尾部
        +---------------+--------------+--------------+---------------+
       |       |prev_fa|      |   fa  | mem | unused |       |next_fa|
       +---------------+--------------+--------------+---------------+
                          ^___________________^^________________________^
           需要重新链接 fa 与 prev_fa 和 next_fa 的关系
            */
          fa = (struct heap_free_area *)((char *)fa + size);
          __heap_link_free_area (heap, fa, prev_fa, next_fa);
        }
    }
      fa->size = fa_size;
    }
  else
    /* 如果找不到 fa,或 mem 在 fa 之前,那么可以简单地
       把 mem 插入 prev_fa 和 fa之间 */
    fa = __heap_add_free_area (heap, mem, size, prev_fa, fa);
  return fa;
}

六、free 解读
解读完 malloc 的代码,再解读 free 应该是件容易的事了,因为 free 中也用到了上面解读过程中的一些函数。
来看代码吧,free 在 free.c 中定义,它实际调用的是 free_to_heap:
static void
free_to_heap (void *mem, struct heap *heap)
{
  size_t size;
  struct heap_free_area *fa;
  /* 检查 mem 是否合法 */
  if (! mem)
    return;
  /* 获取 mem 指向的 malloc 块的的实际大小和起始地址 */
  size = MALLOC_SIZE (mem);
  mem = MALLOC_BASE (mem);
  /* 申请线程锁 */
  __heap_lock (heap);
  /* 把 mem 指向的空间放到 heap 中,__heap_free 在 malloc 中已解读过了  */
  fa = __heap_free (heap, mem, size);
  /* 检查空闲区域大小是否超过了阈值 MALLOC_UNMAP_THRESHOLD */
  if (HEAP_FREE_AREA_SIZE (fa)  start)
    {
      if (unmap_start - start  unmap_end)
    {
      if (end - unmap_end  unmap_start)
    /* 最后,调用 munmap 释放内存 */
    munmap ((void *)unmap_start, unmap_end - unmap_start);
    }
}
在这个过程中值得提到的有两点,似乎是 uClibc 不完善的地方。
1. 在检查到空闲链表为空时,为何不把模块初始化时产生的静态空闲域 initial_fa._fa 赋给 heap 中的 free_areas?而偏偏要到将要释放的空间里割出一块呢?
2. 源代码在将对齐后余下的空间放回 heap 中前有一段注释:
      /* We have to be careful that any left-over bits are large enough to
     return.  Note that we _don't check_ to make sure there's room to
     grow/shrink the start/end by another page, we just assume that
     the unmap threshold is high enough so that this is always safe
     (i.e., it should probably be at least 3 pages).  */
意思是余下的空间应该要足够大,也就是就最小也要有 HEAP_MIN_FREE_AREA_SIZE 这么大,否则上面的对齐就没有意义了。程序中没有去处理这种情况,是因为它假设当阈值设置得足够大时,这种情况发生的机率很小,作者认为它基本上是安全的。
检查了一下官方最新的代码,这部分仍然没有做修改:
http://www.uclibc.org/cgi-bin/viewcvs.cgi/trunk/uClibc/libc/stdlib/malloc/free.c?rev=18427&view=markup

七、结语
之前从来没读过 C 库的代码,这次对 malloc 和 free 代码的走读,原因是开发过程中碰上了 Bug,跟踪到这里面来的。看完后发现 C 库函数远不如想像中的恐怖,希望读到此文的朋友们够循此继续解读下去能


本篇完。
– EOF –

编译基于uclibc的busybox
以前网上文章的介绍都是基于uclibc-0.9.16之前的版本,而编译busybox也是相应的选择静态链接,
但是uclibc的后续版本提供了相应的toolchain,不像0.9.16之前的版本相应的生成gcc,可以直接用来编写基于uclibc的程序。
我的做法是到
www.uclibc.org
下载uclibc的toolchain(gcc-3.3.x),解压缩后,默认的target是i386
中间需要的包包括
binutils-2.14.90.0.6.tar.bz2
ccache-2.3.tar.gz
gcc-3.3.4.tar.bz2
kernel-header-2.4.25.tar.bz2
uClibc-snapshot.tar.bz2
make的过程中会自动下载上述包到/gcc-3.3.x/source/dl,所以也可手动建立dl文件夹,并下载这些包到该文件夹。
make完成之后生成toolchain_i386和toolchain_build_i386文件夹,在/toolchain_i386/bin中就是
交叉编译需要的i386-linux-gcc等工具,/toolchain_i386/lib为uclibc库。

www.busybox.net
下载busybox-1.00,解压
export PATH=/home/xxx/gcc-3.3.x/toolchain_i386/bin:$PATH
make
make dep
make CROSS=i386-linux-
make install
编译完busybox后,不能用系统ldd查看相应程序的动态链接情况,
cd /home/xxx/gcc-3.3.x/toolchain_build_i386/uClibc/utils
make ldd.host
./ldd.host /busybox-1.00/_install/bin/busybox
这时显示的busybox就是链接的uclibc库了。
我的问题是这里生成的uclibc的toolchain和uclibc的库都是用host上gcc和glibc生成的,也就是说 /toolchain_i386/bin/i386-linux-gcc和/toolchain_i386/lib都是通过gcc和glibc生成的,之后再用i386-linux-gcc生成基于uclibc的程序,如果要移植到target上,是把这里的基于host的gcc和glibc编译的 uclibc库移植就可以吗,
还是说在target上运行的uclibc库需要再用这里的i386-linux-gcc交叉编译uclibc.0.9.26.tar.gz源文件,重新生成uclibc库以后才能移植?
(在uclibc-0.9.26的make过程中,export PATH=/home/xxx/gcc-3.3.x/toolchain_i386/bin:$PATH
make CROSS=i386-linux-,这样利用i386-linux-gcc生成的uclibc库与gcc和glibc编译的uclibc库相比较,发现前者相应的文件要小一些。)



本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/78225/showart_1728922.html

你可能感兴趣的:(struct,library,behavior,debugging,Standards)