• 由于缺少对libc.so的认识,以为跟普通的lib包类似,直接把高版本的so软连过去就可以满足安装和升级,造成错误操作直接导致Linux系统崩溃。 错误操作: 在root用户下将/usr/lib/libc.so.6的覆盖,导致系统瘫痪,...

    问题

    由于缺少对libc.so的认识,以为跟普通的lib包类似,直接把高版本的so软连过去就可以满足安装和升级,造成错误操作直接导致Linux系统崩溃。

    错误操作:

    在root用户下将/usr/lib/libc.so.6的覆盖,导致系统瘫痪,所有用户均被强制退出。

    如下示例:

    # root 用户
    cp libc-2.12.1.so /usr/lib/libc.so.6

    分析

    后来查询资料发现,libc.so是软连接到在Linux系统中基本的命令如ls, cp等均依赖该so,其重要性不言而喻。如果不慎删除,重定向,覆盖,都会导致不同程度的异常。而libc.so.6是软连接到具体的版本的libc.so, 如libc-2.17.so

    轻微异常:基本命令无法使用,出现错误

    error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory

    严重异常:所有用户被强制退出,系统崩溃

    服务器崩溃

    解决方法

    解决思路:2步

    1. 首先删除软连接libc.so.6。不同类型的Linux系统该libc的位置不同,我使用的服务器在/usr/lib//usr/lib64下均存在libc.so.6
    2. 根据系统实际的libc.so,再添加libc.so.6的软连接。

    轻微异常

    该异常尽管基本命名无法使用,但是root用户还在,所以定位到libc.so.6之后可以根据解决思路简单实现。示例如下:

    # 假设 /usr/lib/下的libc.so.6的软连接错误的软连到libc.2.17.so, 系统支持的是libc.2.12.1.so
    
    # 现在忘记rm是否可以使用了,如果rm不能使用,则使用 LD_PRELOAD=/lib64/libc-2.12.1.so rm
    rm libc.so.6
    LD_PRELOAD=/lib64/libc-2.12.1.so ln -s libc-2.12.1.so libc.so.6

    系统崩溃

    此时系统已经崩溃,无法再登录进行操作,我们的做法是通过U盘进行登录(U盘存在一个系统),尝试修复系统。使用U盘登录后,原来的系统可以当场文件直接操作,实现解决思路。

    rm libc.so.6
    LD_PRELOAD=/lib64/libc-2.12.1.so ln -s libc-2.12.1.so libc.so.6

    总结

    在修改系统中的so时要非常小心,如果牵扯到系统的底层基础,一定要对so的职能做到简单的了解。

    参考文献

    https://www.linuxidc.com/Linux/2017-02/140994.htm

    展开全文
  • (更新中) 1,ld-linux.so.X的X ... /lib/ld-linux.so.2以及它的64位版本/lib64/ld-linux-x86-64.so.2。 2,ld-linux.so.X 源码 ld-linux.so.X源码在glibc里面,针对的代码是: Rtld.c (g...

    (更新中)

    1,ld-linux.so.X的X

          ld-linux.so.X,其中X为一个数字,在不同的平台上名字也会不同。

          /lib/ld-linux.so.2以及它的64位版本/lib64/ld-linux-x86-64.so.2。

    2,ld-linux.so.X 源码

         ld-linux.so.X源码在glibc里面,针对的代码是: Rtld.c (glibc-2.29\elf):_dl_start_final. "glibc-2.29\elf "目录文件内容大部分和链接有关。

        链接和加载器理论可以参考,《链接器和加载器》,美国莱文(John R.Levine)编写书籍。《链接器和加载器》讲述构建程序的关键工具——链接器和加载器。

         (2019年3月29日)准备建立起一个ld-linux.so的可以调试环境,对这段代码进行研究。

    3,调试glibc中ld的方法

         首先是我安装的环境:ubuntu 14.04

        

     

           

    展开全文
  • 最近在Linux 环境下开发,搞了好几天 Compiler 和 linker,觉得有必要来写一篇关于Linux环境下 ld.so的文章了,google上搜索了很多相关介绍性的文档,发现国内百度上却很少有相关类文档,觉得有必要来梳理一下: ...


    最近在Linux 环境下开发,搞了好几天 Compiler 和 linker,觉得有必要来写一篇关于Linux环境下 ld.so的文章了,google上搜索了很多相关介绍性的文档,发现国内百度上却很少有相关类文档,觉得有必要来梳理一下:



    ld-linux.so.2 是linux下的动态库加载器/链接器,这篇文章主要来讲一下 ld-linux.so.2 是如何和Linux 以及相关应用打交道的。


    1. 什么是 ld.linux.so ? 

    很多现代应用都是通过动态编译链接的,当一个 需要动态链接 的应用被操作系统加载时,系统必须要 定位 然后 加载它所需要的所有动态库文件。 在Linux环境下,这项工作是由ld-linux.so.2来负责完成的,我们可以通过 ldd 命令来查看一个 应用需要哪些依赖的动态库:

    $ ldd `which ls`
          linux-gate.so.1 =>  (0xb7fff000)
          librt.so.1 => /lib/librt.so.1 (0x00b98000)
          libacl.so.1 => /lib/libacl.so.1 (0x00769000)
          libselinux.so.1 => /lib/libselinux.so.1 (0x00642000)
          libc.so.6 => /lib/libc.so.6 (0x007b2000)
          libpthread.so.0 => /lib/libpthread.so.0 (0x00920000)
          /lib/ld-linux.so.2 (0x00795000)
          libattr.so.1 => /lib/libattr.so.1 (0x00762000)
          libdl.so.2 => /lib/libdl.so.2 (0x0091a000)
          libsepol.so.1 => /lib/libsepol.so.1 (0x0065b000)

    当最常见的ls小程序加载时,操作系统会将 控制权 交给 ld-linux.so 而不是 交给程序正常的进入地址。 ld-linux.so.2 会寻找然后加载所有需要的库文件,然后再将控制权交给应用的起始入口。

    上面的ls在启动时,就需要ld-linux.so加载器将所有的动态库加载后然后再将控制权移交给ls程序的入口。


    ld-linux.so.2 man page给我们更高一层的全局介绍, 它是在 链接器(通常是ld)在运行状态下的部件,用来定位和加载动态库到应用的运行地址(或者是运行内存)当中去。通常,动态链接是 在连接阶段当中 隐式指定的。 gcc -W1 options -L/path/included -lxxx 会将 options 传递到ld 然后指定相应的动态库加载。 ELF 文件提供了相应的加载信息, GCC包含了一个特殊的 ELF 头: INTERP, 这个 INTERP指定了 加载器的路径,我们可以用readelf 来查看相应的程序


    $ readelf -l a.out
    
    Elf file type is EXEC (Executable file)
    Entry point 0x8048310
    There are 9 program headers, starting at offset 52
    
    Program Headers:
      Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
      PHDR           0x000034 0x08048034 0x08048034 0x00120 0x00120 R E 0x4
      INTERP         0x000154 0x08048154 0x08048154 0x00013 0x00013 R   0x1
          [Requesting program interpreter: /lib/ld-linux.so.2]
      LOAD           0x000000 0x08048000 0x08048000 0x004cc 0x004cc R E 0x1000
      LOAD           0x000f0c 0x08049f0c 0x08049f0c 0x0010c 0x00110 RW  0x1000
    . . .

    ELF 规格要求,假如 PT_INTERP 存在的话,操作系统必须创建这个 interpreter文件的运行映射,而不是这个程序本身, 控制权会交给这个interpreter,用来定位和加载所有的动态库,







    展开全文
  • linux如何查找.so

    2012-01-18 10:53:51
    Linux 运行的时候,是如何管理共享库(*.so)的?在 Linux 下面,共享库的寻找和加载是由 /lib/ld.so 实现的。 ld.so 在标准路经(/lib, /usr/lib) 中寻找应用程序用到的共享库。 但是,如果需要用到的共享库在非标准...

    从网上找的,来源已经不可考,mark一下,备忘

     

    Linux 运行的时候,是如何管理共享库(*.so)的?在 Linux 下面,共享库的寻找和加载是由 /lib/ld.so 实现的。 ld.so 在标准路经(/lib, /usr/lib) 中寻找应用程序用到的共享库。

    但是,如果需要用到的共享库在非标准路经,ld.so 怎么找到它呢?

    目前,Linux 通用的做法是将非标准路经加入 /etc/ld.so.conf,然后运行 ldconfig 生成 /etc/ld.so.cache。 ld.so 加载共享库的时候,会从 ld.so.cache 查找。

    传统上,Linux 的先辈 Unix 还有一个环境变量:LD_LIBRARY_PATH 来处理非标准路经的共享库。ld.so 加载共享库的时候,也会查找这个变量所设置的路经。

    LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./lib

    export LD_LIBRARY_PATH

    但是,有不少声音主张要避免使用 LD_LIBRARY_PATH 变量,尤其是作为全局变量。这些声音是:

    * LD_LIBRARY_PATH is not the answer - http://prefetch.net/articles/linkers.badldlibrary.html

    * Why LD_LIBRARY_PATH is bad - http://xahlee.org/UnixResource_dir/_/ldpath.html 

    * LD_LIBRARY_PATH - just say no - http://blogs.sun.com/rie/date/20040710

    解决这一问题的另一方法是在编译的时候通过 -R<path> 选项指定 run-time path。

    1. 往/lib和/usr/lib里面加东西,是不用修改/etc/ld.so.conf的,但是完了之后要调一下ldconfig,不然这个library会找不到

    2. 想往上面两个目录以外加东西的时候,一定要修改/etc/ld.so.conf,然后再调用ldconfig,不然也会找不到。

    比如安装了一个mysql到/usr/local/mysql,mysql有一大堆library在/usr/local/mysql/lib下面,这时就需要在/etc/ld.so.conf下面加一行/usr/local/mysql/lib,保存过后ldconfig一下,新的library才能在程序运行时被找到。

    3. 如果想在这两个目录以外放lib,但是又不想在/etc/ld.so.conf中加东西(或者是没有权限加东西)。那也可以,就是export一个全局变量LD_LIBRARY_PATH,然后运行程序的时候就会去这个目录中找library。一般来讲这只是一种临时的解决方案,在没有权限或临时需要的时候使用。

    4. ldconfig做的这些东西都与运行程序时有关,跟编译时一点关系都没有。编译的时候还是该加-L就得加,不要混淆了。

    5. 总之,就是不管做了什么关于library的变动后,最好都ldconfig一下,不然会出现一些意想不到的结果。不会花太多的时间,但是会省很多的事。

    LD_LIBRARY_PATH 这个环境变量是大家最为熟悉的,它告诉loader:在哪些目录中可以找到共享库。可以设置多个搜索目录,这些目录之间用冒号分隔开。在linux下,还提供了另外一种方式来完成同样的功能,你可以把这些目录加到/etc/ld.so.conf中,然后调用ldconfig。当然,这是系统范围内全局有效的,而环境变量只对当前shell有效。按照惯例,除非你用上述方式指明,loader是不会在当前目录下去找共享库的,正如shell不会在当前目前找可执行文件一样。

     

    展开全文
  • 前面“Linux应用程序Helloworld入门”已经提到在Linux下每个可执行文件都依赖于几个最为基本的动态库,其中一个就是linux-gate.so.1。 从上面ldd给出的结果可以看出,这个linux-gate.so.1动态库有一些异样...


    前面“Linux应用程序Helloworld入门”已经提到在Linux下每个可执行文件都依赖于几个最为基本的动态库,其中一个就是linux-gate.so.1。



    从上面ldd给出的结果可以看出,这个linux-gate.so.1动态库有一些异样,libc.so.6的实际动态库路径在/lib/tls/i686/cmov/libc.so.6,而ld-linux.so.2是在/lib/ld-linux.so.2。那么不禁要问一个问题linux-gate.so.1这个动态库的路径是什么,是文件系统中那个文件呢?其实这个文件是内核映射上去的,并非存在实际的动态库文件,对于这个具体问题我们后续再做详细分析,这里仅仅做如何获取linux-gate.so.1动态库的方法。


    通常情况下,比如在suse10, suse11系统上,linux-gate.so.1被映射到ffffe000-fffff000这个高端内存段里面。此时将这段内存导出到文件比较简单,可以使用下面脚本,帮助各位导出:

    #!/bin/bash
    VDSO_FILE_NAME=linux-gate.dso
    cat /proc/self/maps|grep "vdso"
    VDSO_ADDR=`cat /proc/self/maps|grep "vdso" |awk -F '-' '{print $1 }'`
    echo "Current VDSO address is 0x$VDSO_ADDR"
    
    VDSO_BLOCK=`echo |awk '{print substr("'${VDSO_ADDR}'",1,5)}'`
    ((SKIP_BLOCKS=16#$VDSO_BLOCK))
    echo "We have $SKIP_BLOCKS blocks before VDSO library"
    
    echo "Ready to generate $VDSO_FILE_NAME from block $SKIP_BLOCKS"
    dd if=/proc/self/mem of=$VDSO_FILE_NAME bs=4096 skip=$SKIP_BLOCKS count=1
    
    echo "Generate $VDSO_FILE_NAME Done"


    在suse系统上执行的结果:

    ~> ./cat_linux_gate_so.sh
    ffffe000-fffff000 ---p 00000000 00:00 0          [vdso]
    Current VDSO address is 0xffffe000
    We have 1048574 blocks before VDSO library
    Ready to generate linux-gate.dso from block 1048574
    1+0 records in
    1+0 records out
    4096 bytes (4.1 kB) copied, 4.2e-05 seconds, 97.5 MB/s
    Generate linux-gate.dso Done
    
    ~> file -b linux-gate.dso
    ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), stripped
    ~> objdump -T linux-gate.dso
    
    
    linux-gate.dso:     文件格式 elf32-i386
    
    
    DYNAMIC SYMBOL TABLE:
    ffffe400 l    d  .text  00000000              .text
    ffffe478 l    d  .eh_frame_hdr  00000000              .eh_frame_hdr
    ffffe49c l    d  .eh_frame      00000000              .eh_frame
    ffffe620 l    d  .useless       00000000              .useless
    ffffe400 g    DF .text  00000014  LINUX_2.5   __kernel_vsyscall
    00000000 g    DO *ABS*  00000000  LINUX_2.5   LINUX_2.5
    ffffe440 g    DF .text  00000007  LINUX_2.5   __kernel_rt_sigreturn
    ffffe420 g    DF .text  00000008  LINUX_2.5   __kernel_sigreturn

    在ubuntu 上情况比较复杂,在此也耽误了不少时间,因为ubuntu映射到的内存地址是不固定的,每个进程映射的位置都是不同的。

    多次执行:

    cat /proc/self/maps|grep "vdso"

    b7f47000-b7f48000 r-xp b7f47000 00:00 0          [vdso]

    b7f5f000-b7f60000 r-xp b7f5f000 00:00 0          [vdso]

    b7f54000-b7f55000 r-xp b7f54000 00:00 0          [vdso]


    因此上面脚本无法实现同一个进程内映射内存导出。为了实现同一进程内导出,这里采用简单C编程的方法实现。

    基本原理和上面脚本一致,首先通过/proc/self/maps找到vsdo映射内存的地址,然后导出映射内存到文件linux-gate.dso。

    int main(int argc, char **argv)
    {
    	FILE *pFile = NULL;
    	void *paddr = NULL;
    
    	char buffer[BUFFER_SIZE];
    	char address[BUFFER_SIZE];
    	char block[BLOCK_SIZE];
    
    	char c;
    	int i, ineedreset, iblocks, iSize;
    	
    	pFile = fopen("/proc/self/maps", "r");
    	if (NULL == pFile)
    	{
    		printf("/proc/self/maps fopen failed, error!\r\n");
    		return 1;
    	}
    
    	/* 查找vdso动态库映射内存位置  */
    	i = 0;
    	ineedreset = 1;
    	memset(buffer, 0, BUFFER_SIZE);
    	while(1) 
    	{
    		c = fgetc (pFile);
    		if (c != EOF) 
    		{
    			printf("%c", c);
    			if (c == '\r' || c == '\n')
    			{
    				i = 0;
    				ineedreset = 1;
    			} else
    			{
    				if (ineedreset)
    				{
    					if (NULL != strstr(buffer, "vdso"))
    					{
    						printf("I have got vdso section.\r\n");
    						break;
    					}
    					memset(buffer, 0, BUFFER_SIZE);
    					ineedreset = 0;
    				}			
    				buffer[i++] = c;
    			}
    		}else
    		{
    			break;
    		}
        }
    
    	printf("vsdo line is:%s\r\n", buffer);
    	fclose(pFile);
    	pFile = NULL;
    	
    	/* 获取起始地址 */
    	memset(address, 0, BUFFER_SIZE);
    	for (i = 0; buffer[i] != '-'; i++)
    	{
    		address[i] = buffer[i];
    		if (buffer[i] == '-')
    			break;
    	}
    
    	paddr = (void *) Hex2Ulong(address);
    	printf("Current VDSO address is 0x%x\r\n", paddr);
    	iblocks = (unsigned long)paddr / BLOCK_SIZE;
    	printf("We have %d blocks before VDSO library\r\n", iblocks);
    	printf("Ready to generate linux-gate.dso from block %d\r\n", iblocks);
    
    	/* 导出vdso动态文件 */
    	pFile = fopen("./linux-gate.dso", "w");
    	if (NULL == pFile)
    	{
    		printf("fopen linux-gate.dso failed, exit!\r\n");
    		return 1;
    	}
    
    	printf("Head:0x%x-%c-%c-%c\r\n", *((char *)paddr + 0),*((char *)paddr + 1),*((char *)paddr + 2),*((char *)paddr + 3));
            memcpy(block, paddr, BLOCK_SIZE);
    	iSize = fwrite(block, 1, BLOCK_SIZE, pFile);
    	if (BLOCK_SIZE != iSize)
    	{
    		perror("fwrite error:\r\n");
    	}
    	printf("copy %d/%d bytes from 0x%x to the file\r\n", iSize, BLOCK_SIZE, paddr);
    
    	fclose(pFile);
    	printf("Generate linux-gate.dso Done\r\n");
    
    	return 0;
    }



    
    

    然后看下导出的结果:

    这样我们就能在动态映射的情况下也能导出动态库。app_linux_gate_so.c如果做适当修改就能导出所有映射的动态内存库,用于DEBUG和验证了。

    参考资料:

    【1】二进制,八进制,十进制和十六进制 之间的关系转换

    注:这里使用的unsigned long Hex2Ulong(char s[])是简单实现,供参考,相见参考资料

    #define YES 1
    #define NO  0
    
    unsigned long Hex2Ulong(char s[])
    {
        int i;
        unsigned long n;
        int inhex, digital;
    
        i = 0;
        if (s[i] == '0')
        {
            i++;
            if (s[i] == 'x' || s[i] == 'X')
            {
                i++;
            }
        }
    
        n = 0;
        inhex = YES;
        for (; inhex == YES; i++)
        {
            if (s[i] >= '0' && s[i] <= '9')
                digital = s[i] - '0';
            else if (s[i] >= 'a' && s[i] <= 'f')
                digital = s[i] - 'a' + 10;
            else if (s[i] >= 'A' && s[i] <= 'F')
                digital = s[i] - 'A' + 10;
            else
            {
                inhex = NO;
                break;
            }
            n = 16 * n + digital;
        }
    
        return n;
    }
    



    展开全文
  • linux .so文件详解

    2014-03-07 16:36:08
    linux下文件的类型是不依赖于其后缀名的,但一般来讲: .o,是目标文件,相当于windows中的.obj文件 .so 为共享库,是shared object,用于动态连接的,和dll差不多 .a为静态库,是好多个.o合在一起,用于静态连接 .la为...
  • Linux下整合.so库到java工程中的过程中,使用JNA遇到加载不到so的问题。现在总结一下: 1.在Linux下,IDEA中。.so的库只会识别在/target/classes/路径下。因此手动直接将.so放到此处就可以识别。 (注意到没有,这...
  • linux下误删libc.so.6解决方法 参考网址:https://blog.csdn.net/ydyang1126/article/details/53424101 yum install安装了一个软件之后,发现用什么命令都不好使了。错误提示信息: ls: error while loading ...
  • libc.so.6 是c运行时库 glibc的软链接,而系统几乎所有程序都依赖c运行时库。程序启动和运行时,是根据libc.so.6 软链接找到glibc库。删除libc.so.6将导致系统的几乎所有程序不能工作。  每个glibc.so文件有它...
  • Linux下生成.so文件

    2016-07-28 14:55:08
    linux下的.so文件即Shared Libraries。Shared Library 是程序运行时加载的库文件。当一个shared library 被成功的安装以后,之后启动的所有程序都会自动使用最新的shared library。也就是说,生成一个.so文件并告诉...
  • libz.so.1 只是一个符号链接,如果你只是这个链接文件没了,而真正的库文件还在,那就不要紧。可以用以下方法恢复:ls /usr/lib/libz*正常情况下,你应该看到libz.so libz.so.1 libz.so.1.y.z其中 libz.so.1.y.z 才...
  • linux-libc.so.6

    2020-06-05 16:20:41
    安装守护程序的时候有时候会报错,可能缺少这个包
  • .so .so.1区别

    2019-05-11 15:06:35
    细深的先不讲,我只知道使用.so时是gcc main.c-ltest 使用.so.1时是gcc main.c test.so.1
  • Linux下的.so文件编写

    2017-08-19 11:34:41
    Linux下的.so是基于linux下的动态链接,其功能和作用类似与windows下.dll文件。 下面是关于.so的介绍: 一、引言 通常情况下,对函数库的链接是放在编译时期(compile time)完成的。所有相关的对象文件...
  • linux-vdso.so.1介绍

    2015-02-28 14:18:41
    这段时间看Linux内核源码的时候,经常碰到vdso这个东西(像在Feature-fixup中,获取时间等操作时),网上搜了一下,才知道了含义,原来这是Linux为了解决和glibc兼容而想出的绝招啊。下面是从Fedora中文邮件列表转过来...
  • 原文链接:...   linux下生成.so文件和.a文件 test.h 1 #ifndef _TEST_H_ 2 #define _TEST_H_ 3 4 void TestA(); 5 void TestB(); 6 7 #endif   t...
  • 2. 将.so文件到/lib或/usr/lib目录下(不推荐) 3. 将库文件绝对路径添加到/etc/ls.so.conf文件中,并用ldconfig命令重建ld.so.cache文件(不推荐) 4. 增加编译链接参数 (LDFLAGS = -Wl,--hash-s...
  • 一、前言 如果有公司需要使用你们产品的...二、静态库.a与动态库.so的生成与区别 .o文件 :二进制目标文件,可用于打包成库文件也可以链接生成可执行文件; c文件编译后链接,生成可执行文件 gcc t...
  • linux 中的.so和.a文件

    2012-01-21 10:44:01
    Linux下的.so是基于Linux下的动态链接,其功能和作用类似与windows下.dll文件。 下面是关于.so的介绍: 一、引言 通常情况下,对函数库的链接是放在编译时期(compile time)完成的。所有相关的对象文件(object ...
  • linux中,libc.so.6动态库的存在决定了很多命令是否能使用,如:cp、mv、ls、ln等 可幸的是cp和export可用 cd /lib64 export LD_PRELOAD=/lib64/libc-2.12.so 我自个出现这个误操作的原因是需要升级centos glibc到...
1 2 3 4 5 ... 20
收藏数 370,556
精华内容 148,222
热门标签