Bug 101837 - lstat relocation error when called from shared library
Summary: lstat relocation error when called from shared library
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Red Hat Linux
Classification: Retired
Component: glibc
Version: 8.0
Hardware: i686
OS: Linux
medium
medium
Target Milestone: ---
Assignee: Jakub Jelinek
QA Contact: Brian Brock
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2003-08-07 13:59 UTC by Jeff Woods
Modified: 2016-11-24 14:48 UTC (History)
1 user (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2003-08-07 14:06:58 UTC
Embargoed:


Attachments (Terms of Use)

Description Jeff Woods 2003-08-07 13:59:18 UTC
From Bugzilla Helper:
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624

Description of problem:
When lstat is called from a routine in a shared library, the following error is
generated when a binary linked against the shared library is executed:

<binary>: relocation error: <shared library>: undefined symbol: lstat

This also holds true for lstat64, fstat, and fstat64.

This appears to be a problem with the glibc headers, because in sys/stat.h,
lstat is #defined to translate to __lxstat.  lstat is not a symbol in libc,
where __lxstat is.  For some reason, the define is not being applied properly
and lstat remains unresolved.

As a work-around, the #define from sys/stat.h can be removed and inserted at the
top of the shared library source file which calls lstat, and everything works
correctly (see below).

Version-Release number of selected component (if applicable):
glibc-2.3.2-4.80.6

How reproducible:
Always

Steps to Reproduce:
Can be reproduced by building the following source code:

==== main.c ====

#include <stdio.h>

int size(char *);

int main(int argc, char **argv)
{
    int s;

    s = size(argv[1]);
    fprintf(stdout, "Size of %s is %d\n", argv[1], s);

    return 0;
}

==== size.c ====

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int size(char *file)
{
    struct stat sbuf;

    if (lstat(file, &sbuf) < 0)
    {
        perror("lstat");
        return 0;
    }

    fprintf(stdout, "File size: %d\n",sbuf.st_size);
    return sbuf.st_size;
}

Then:

% gcc -c -o size.o size.c
% ld -G -o libsize.so size.o
% gcc -L. -lsize -o main main.c
% export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
% ./main main.c

Actual Results:  Received the relocation error:

./main: relocation error: ./libsize.so: undefined symbol: lstat


Expected Results:  The binary should have executed without the relocation error.

Additional info:

There is a work-around for this, though it is somewhat awkward.  Modifying the
size.c file to include the #define from sys/stat.h corrects the problem:

==== size.c ====
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

static __inline__ int lstat (__const char *__path,
                                     struct stat *__statbuf) __THROW
{
      return __lxstat (_STAT_VER, __path, __statbuf);
}

int size(char *file)
{
    struct stat sbuf;

    if (lstat(file, &sbuf) < 0)
    {
        perror("lstat");
        return 0;
    }

    fprintf(stdout, "File size: %d\n",sbuf.st_size);
    return sbuf.st_size;
}

Rebuild using the steps above, and everything works correctly.

Comment 1 Jakub Jelinek 2003-08-07 14:06:58 UTC
The problem is in how you are building the shared library.
Never ever use ld directly unless you know what you are doing.
Use gcc -shared -o libsize.so size.o
to link it instead. lstat etc. are not #define's, they are extern inline
functions, but without optimizations (ie. how you are compiling it) they are
not inlined. gcc driver during linking ensures the library is linked against
all necessary libraries (like -lc, which actually expands to libc.so.6 dependency
and libc_nonshared.a).


Note You need to log in before you can comment on or make changes to this bug.