文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>uClibc和Glibc区别

uClibc和Glibc区别

时间:2009-03-22  来源:oldstorm

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).

<other things as we notice them>

******************************  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 <= 0x7f.
5) uClibc allows glibc-like custom streams.  However, no in-buffer seeking is
   done.
6) The functions fcloseall() and __fpending() can behave differently than their
   glibc counterparts.
7) uClibc's setvbuf is more restrictive about when it can be called than glibc's
   is.  The standards specify that setvbuf must occur before any other operations
   take place on the stream.
8) Right now, %m is not handled properly by printf when the format uses positional
   args.
9) The FILEs created by glibc's fmemopen(), open_memstream(), and fopencookie()
   are not capable of wide orientation.  The corresponding uClibc routines do
   not have this limitation.
10) For scanf, the C99 standard states "The fscanf function returns the value of
    the macro EOF if an input failure occurs before any conversion."  But glibc's
    scanf does not respect conversions for which assignment was surpressed, even
    though the standard states that the value is converted but not stored.

glibc bugs that Ulrich Drepper has refused to acknowledge or comment on
  ( http://sources.redhat.com/ml/libc-alpha/2003-09/ )
-----------------------------------------------------------------------
1) The C99 standard says that for printf, a %s conversion makes no special
   provisions for multibyte characters.  SUSv3 is even more clear, stating
   that bytes are written and a specified precision is in bytes.  Yet glibc
   treats the arg as a multibyte string when a precision is specified and
   not otherwise.
2) Both C99 and C89 state that the %c conversion for scanf reads the exact
   number of bytes specified by the optional field width (or 1 if not specified).
   uClibc complies with the standard.  There is an argument that perhaps the
   specified width should be treated as an upper bound, based on some historical
   use.  However, such behavior should be mentioned in the Conformance document.
3) glibc's scanf is broken regarding some numeric patterns.  Some invalid
   strings are accepted as valid ("0x.p", "1e", digit grouped strings).
   In spite of my posting examples clearly illustrating the bugs, they remain
   unacknowledged by the glibc developers.
4) glibc's scanf seems to require a 'p' exponent for hexadecimal float strings.
   According to the standard, this is optional.
5) C99 requires that once an EOF is encountered, the stream should be treated
   as if at end-of-file even if more data becomes available.  Further reading
   can be attempted by clearing the EOF flag though, via clearerr() or a file
   positioning function.  For details concerning the original change, see
   Defect Report #141.  glibc is currently non-compliant, and the developers
   did not comment when I asked for their official position on this issue.
6) glibc's collation routines and/or localedef are broken regarding implicit
   and explicit UNDEFINED rules.

More to follow as I think of it...

Profiling:
-------------------------------------------------------------------

uClibc no longer supports 'gcc -fprofile-arcs  -pg' style profiling, which
causes your application to generate a 'gmon.out' file that can then be analyzed
by 'gprof'.  Not only does this require explicit extra support in uClibc, it
requires that you rebuild everything with profiling support.  There is both a
size and performance penalty to profiling your applications this way, as well
as Heisenberg effects, where the act of measuring changes what is measured.

There exist a number of less invasive alternatives that do not require you to
specially instrument your application, and recompile and relink everything.

The OProfile system-wide profiler is an excellent alternative:
      http://oprofile.sourceforge.net/

Many people have had good results using the combination of Valgrind
to generate profiling information and KCachegrind for analysis:
      http://developer.kde.org/~sewardj/
      http://kcachegrind.sourceforge.net/

Prospect is another alternative based on OProfile:
      http://prospect.sourceforge.net/

And the Linux Trace Toolkit (LTT) is also a fine tool:
    http://www.opersys.com/LTT/

FunctionCheck:
    http://www710.univ-lyon1.fr/~yperret/fnccheck/
    原文链接: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
  • 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

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 <[email protected]>.

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 <[email protected]>.

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 <[email protected]> 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 <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 <[email protected]> when he worked for the FSF. In 2001 The GNU C Library Steering Committee <[email protected]>, 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 webmasterswww.gnu.org. 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_HEAP_EXTEND_SIZE ? MALLOC_HEAP_EXTEND_SIZE : MALLOC_ROUND_UP_TO_PAGE_SIZE (size)); /* 向内核申请空间 */ block = mmap (0, block_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0); /* 申请成功,将空间放入 heap 的空闲区域 */ if (block != (void *)-1) { /* 申请线程锁 */ __heap_lock (heap); /* 将空间放入 heap 的空闲区域 */ __heap_free (heap, block, block_size); /* 重新申请一次空间 */ mem = __heap_alloc (heap, &size); /* 释放线程锁 */ __heap_unlock (heap); } } if (mem) { /* 申请成功,将 mem 指向 ADDR 处 +--------+---------+-------------------+ | SIZE |(unused) | allocation ... | +--------+---------+-------------------+ ^ BASE ^ ADDR ^ mem */ mem = MALLOC_SETUP (mem, size); } else MALLOC_DEBUG (-1, "malloc: returning 0"); return mem; }

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_MIN_FREE_AREA_SIZE) { /* 如果在这个空闲区域中剩余的空间不足以维持一个 heap_free_area 节点, 则把这个区域从链表中移除 __heap_delete 只是个简单的链表操作,在 heap.h 中定义 */ __heap_delete (heap, fa); /* 修改大小,实际申请的空间要大于传入的 size */ size = fa_size; } else /* 如果这个区域中还有空闲空间,就把 heap_free_area 节点中 的 size 减小 size就可以了: 分配前: __________ 空闲空间 __________ __ 空闲空间信息 __ / \ / \ +-------------------------------+--------------------+ | | heap_free_area | +-------------------------------+--------------------+ \__________ fa->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) <= end) { size_t fa_size = 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) < MALLOC_UNMAP_THRESHOLD) /* 没有超过,只需要释放线程锁就可以了 */ __heap_unlock (heap); else /* 超过了,则把多余的空间释放,交还给系统内核管理 */ { unsigned long start = (unsigned long)HEAP_FREE_AREA_START (fa); unsigned long end = (unsigned long)HEAP_FREE_AREA_END (fa); /* 从空闲链表中删除该空闲区域 */ __heap_delete (heap, fa); if (__heap_is_empty (heap)) /* 如果空闲链表为空 */ { /* 保留 MALLOC_MIN_SIZE 大小的区域给 heap,作为空闲区域 */ __heap_free (heap, (void *)start, MALLOC_MIN_SIZE); start += MALLOC_MIN_SIZE; } /* 使要释放的空间的起止地址按页对齐,开始地址向上对齐,结束地址向下对齐 */ unmap_start = MALLOC_ROUND_UP_TO_PAGE_SIZE (start); unmap_end = MALLOC_ROUND_DOWN_TO_PAGE_SIZE (end); /* 将对齐后余下的空间再放回 heap 中 */ if (unmap_start > start) { if (unmap_start - start < HEAP_MIN_FREE_AREA_SIZE) unmap_start += MALLOC_PAGE_SIZE; __heap_free (heap, (void *)start, unmap_start - start); } if (end > unmap_end) { if (end - unmap_end < HEAP_MIN_FREE_AREA_SIZE) unmap_end -= MALLOC_PAGE_SIZE; __heap_free (heap, (void *)unmap_end, end - unmap_end); } /* 系统调用前需要先释放锁 */ __heap_unlock (heap); if (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库相比较,发现前者相应的文件要小一些。)

 

排行榜 更多 +
rento大富翁手游

rento大富翁手游

休闲益智 下载
冲撞赛车3无限金币版

冲撞赛车3无限金币版

赛车竞速 下载
电动火车模拟器内置菜单

电动火车模拟器内置菜单

赛车竞速 下载