AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 77754998
Accepted
StoneThrow
StoneThrow
Asked: 2024-01-04 06:41:55 +0800 CST2024-01-04 06:41:55 +0800 CST 2024-01-04 06:41:55 +0800 CST

Por que esta biblioteca compartilhada não possui uma dependência esperada?

  • 772

Estou tentando criar uma biblioteca compartilhada, libfunc.soque depende de outra biblioteca compartilhada (especificamente libuv.so, mas acho que a biblioteca específica não é relevante para a questão). Ou seja, quando executo ldd libfunc.so, quero ver a dependência de libfunc.sopara libuv.so.

Este é o código que quero compilar libfunc.so:

#include <uv.h>

int func() {
  uv_timespec64_t now;

  uv_clock_gettime(UV_CLOCK_REALTIME, &now);

  return 0;
}

... eu compilo assim:

$ cc --version && cc -fpic -ggdb -Wall -c -o func.o func.c
cc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ cc -shared -o libfunc.so func.o -fpic -ggdb -Wall -luv
$

...quando executo ldd libfunc.sonão vejo a dependência desejada em libuv.so:

$ ldd ./libfunc.so
        linux-vdso.so.1 (0x00007fff827ae000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f14b291e000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f14b2b54000)
$

... ou seja, eu queria ver algo como:

        linux-vdso.so.1 (0x00007ffcbbdca000)
        libuv.so.1 => /lib/x86_64-linux-gnu/libuv.so.1 (0x00007f781b25c000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f781b034000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f781b2a2000)

Minha pergunta é: por que não libuv.soaparece uma dependência e o que preciso fazer para criar essa dependência?

Meu entendimento é provavelmente rudimentar e incompleto, mas pensei que criar um relacionamento de dependência seria algo como 1) escrever código que chama uma função de uma biblioteca (compartilhada), 2) compilar código de objeto, 3) criar biblioteca (compartilhada) de código de objeto ao vincular a uma biblioteca que define o símbolo ausente.

Inspecionando libfunc.so, vejo símbolos indefinidos esperados para libuvsímbolos:

$ nm libfunc.so | grep U
0000000000002000 r __GNU_EH_FRAME_HDR
                 U __stack_chk_fail@GLIBC_2.4
                 U uv_clock_gettime
$

Para algum contexto, estou tentando criar um MVCE a partir de um projeto maior. Especificamente, esse projeto maior cria uma biblioteca compartilhada que depende do libuv. Porém , quando executo ldda biblioteca compartilhada do projeto maior, ela mostra uma dependência libuv(foi aí que obtive a saída para a saída ldd "desejada", acima).

O projeto maior é muito grande para eu postar aqui no Stack Overflow, mas ao inspecionar sua makesaída, acredito que meu MCVE está compilando/vinculando com os mesmos sinalizadores. Por exemplo, algumas linhas de compilação e a linha de link do projeto maior são:

cc -fpic -ggdb -Wall   -c -o file1.o file1.c
cc -fpic -ggdb -Wall   -c -o file2.o file2.c
cc -shared -o libplugin.so file1.o file2.o -fpic -ggdb -Wall -luv

(há mais arquivos compilados que compõem libplugin.so, mas o subconjunto acima transmite a essência disso - os sinalizadores de compilação são uniformes para todos os arquivos compilados)


Atualização: se eu adicionar uma chamada uv_close()no código da minha biblioteca compartilhada, o relacionamento de dependência desejado aparecerá! Ou seja:

#include <uv.h>

int func() {
  uv_timespec64_t now;

  uv_clock_gettime(UV_CLOCK_REALTIME, &now);
  uv_close(NULL, NULL); // <= Adding this line causes the desired dependency to show up in ldd

  return 0;
}
$ cc -fpic -ggdb -Wall -c -o func.o func.c
$ cc -shared -o libfunc.so func.o -fpic -ggdb -Wall -luv
$ ldd ./libfunc.so
        linux-vdso.so.1 (0x00007ffc1e323000)
        libuv.so.1 => /lib/x86_64-linux-gnu/libuv.so.1 (0x00007f412b761000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f412b539000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f412b7a1000)
$

Alguém pode me ajudar a entender essa observação? Por que chamar uv_clock_gettime()vs. uv_close()se comporta dessa maneira em relação ao relacionamento de dependência criado na biblioteca compartilhada?


Atualização: eu queria explorar um pouco mais o comentário de @WeatherVane sobre RE: otimização. Aqui, novamente, meu entendimento é provavelmente rudimentar e incompleto, mas pensei que se eu compilasse com -O0, isso forçaria o compilador a não otimizar nada e, portanto, induziria a dependência mesmo quando minha biblioteca compartilhada chamasse apenas uv_clock_gettime(). Mas a realidade não correspondeu a essa ideia: voltando func.ca apenas chamar uv_clock_gettime()e compilar tudo com o -O0, ainda não vejo dependência do libuv. Ou seja:

$ cc -fpic -ggdb -O0 -Wall -c -o func.o func.c # Note the -O0
$ cc -shared -O0 -o libfunc.so func.o  -fpic -ggdb -luv # Note the -O0
$ ldd ./libfunc.so
        linux-vdso.so.1 (0x00007fff8e724000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fee6f03e000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fee6f274000)

Eu queria explorar a sugestão do @Barmar de excluir a possibilidade de otimização imprimindo o valor de now, mas mesmo essa versão do código resultou em não haver a dependência desejada. Ou seja:

#include <inttypes.h>
#include <stdio.h>
#include <uv.h>

int func() {
  uv_timespec64_t now;

  uv_clock_gettime(UV_CLOCK_REALTIME, &now);
  printf("%" PRId64 "\n", now.tv_sec);

  return 0;
}
$ cc -fpic -ggdb -Wall -c -o func.o func.c
$ cc -shared -o libfunc.so func.o  -fpic -ggdb -luv
$ ldd ./libfunc.so
        linux-vdso.so.1 (0x00007ffd72bdf000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0a89964000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f0a89b9a000)

Explorando a sugestão de @EmployedRusso, o readelfresultado é:

$ readelf -Ws /usr/local/lib/libuv.so.1 | grep uv_close
   337: 0000000000013766   427 FUNC    GLOBAL DEFAULT   14 uv_close
   735: 0000000000013766   427 FUNC    GLOBAL DEFAULT   14 uv_close
$ readelf -Ws /usr/local/lib/libuv.so.1 | grep uv_clock_gettime
   341: 00000000000136a0   178 FUNC    GLOBAL DEFAULT   14 uv_clock_gettime
  1120: 00000000000136a0   178 FUNC    GLOBAL DEFAULT   14 uv_clock_gettime
$

Estou atualizando esta postagem com algumas observações baseadas na resposta de @EmployedRusso porque são relevantes, mas difíceis de adicionar como comentário.

Com a versão da biblioteca compartilhada que chama apenas uv_clock_gettime, o uso da -yopção vinculador revela:

$ cc -shared -Wl,-y,uv_clock_gettime,-y,uv_close -o libfunc.so func.o  -fpic -ggdb -luv
/usr/bin/ld: func.o: reference to uv_clock_gettime
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libuv.so: definition of uv_close
$

... e com a versão da biblioteca compartilhada que faz referência a ambos uv_clock_gettimee uv_close, a -yopção do vinculador revela:

$ cc -shared -Wl,-y,uv_clock_gettime,-y,uv_close -o libfunc.so func.o  -fpic -ggdb -luv
/usr/bin/ld: func.o: reference to uv_close
/usr/bin/ld: func.o: reference to uv_clock_gettime
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libuv.so: definition of uv_close

... que se alinha com a explicação de @EmployedRusso sobre símbolos referenciados vs. símbolos encontrados DT_NEEDEDvs.

Além disso, com a versão da biblioteca compartilhada que faz referência apenas a uv_clock_gettime, o uso do --no-as-neededsinalizador do vinculador realmente "forçou" a inclusão da dependência:

$ cc -shared -Wl,--no-as-needed -o libfunc.so func.o  -fpic -ggdb -luv
$ ldd ./libfunc.so
        linux-vdso.so.1 (0x00007ffe312cf000)
        libuv.so.1 => /lib/x86_64-linux-gnu/libuv.so.1 (0x00007f36fe4f8000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f36fe2d0000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f36fe538000)
$
c
  • 1 1 respostas
  • 68 Views

1 respostas

  • Voted
  1. Best Answer
    Employed Russian
    2024-01-04T11:36:26+08:002024-01-04T11:36:26+08:00

    Outra coisa que notei: precisei usar grep /usr/local/lib/libuv.so.1em vez de /lib/x86_64-linux-gnu/libuv.so.1porque este último não tinha o uv_clock_gettimesímbolo.

    Essa é provavelmente a resposta. Eu estou supondo que

    1. /lib/x86_64-linux-gnu/libuv.so.1está sendo usado no momento do link, e
    2. Seu GCC está configurado para passar -Wl,--as-neededpor padrão.

    Se ambos forem verdadeiros, então, quando você vincula func.oisso não faz referência a uv_close, o vinculador encontra /lib/x86_64-linux-gnu/libuv.so.1, mas descobre que não satisfaz nenhum símbolo e, portanto, não o registra como DT_NEEDEDfor libfoo.so.

    Quando você muda func.opara também require uv_close, o vinculador observa que /lib/x86_64-linux-gnu/libuv.so.1é necessário satisfazer esse símbolo e o registra na DT_NEEDEDtag for libfoo.so.


    Para confirmar essas suposições, vincule-se libfoo.soà -Wl,-y,uv_clock_gettime,-y,uv_closebandeira. Isso deve mostrar quais binários fazem referência e quais definem os dois símbolos.

    Você também pode vincular -Wl,--no-as-needed- nesse caso, libuv.so.1aparecerá independentemente de satisfazer algum símbolo.

    • 1

relate perguntas

  • Multiplicação mais rápida que *

  • Usando uma macro para comprimento de string no especificador de formato scanf () em C

  • Como você pode definir o tipo de dados de #define para long double?

  • Ponteiros const incompatíveis

  • Mudança de cor não gradual no OpenGL

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle?

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Quando devo usar um std::inplace_vector em vez de um std::vector?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Marko Smith

    Estou tentando fazer o jogo pacman usando apenas o módulo Turtle Random e Math

    • 1 respostas
  • Martin Hope
    Aleksandr Dubinsky Por que a correspondência de padrões com o switch no InetAddress falha com 'não cobre todos os valores de entrada possíveis'? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer Quando devo usar um std::inplace_vector em vez de um std::vector? 2024-10-29 23:01:00 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST
  • Martin Hope
    MarkB Por que o GCC gera código que executa condicionalmente uma implementação SIMD? 2024-02-17 06:17:14 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve