Objetos compartilhados e vinculação de tempo de execução
Por padrão, os programas são vinculados de modo que uma referência a um símbolo importado de um objeto compartilhado esteja ligado a essa definição no tempo de carregamento.
Isso é verdade mesmo se o programa, ou outro objeto compartilhado requerido pelo programa, define o mesmo símbolo.
- linker de tempo de execução
- Um objeto compartilhado que permite que símbolos sejam religados para programas adequadamente vinculados
Você inclui o linker de tempo de execução em um programa vinculando o programa com a opção -brtl . Esta opção tem os seguintes efeitos:
- Uma referência ao linker de tempo de execução é adicionada ao seu programa. Quando a execução do programa começa, o código de inicialização (/lib/crt0.o) chamará o linker de tempo de execução antes que a função principal seja chamada.
- Todos os arquivos de entrada que são objetos compartilhados são listados como dependentes do seu programa na seção de carregadores do seu programa. Os objetos compartilhados são listados na mesma ordem em que foram especificados na linha de comando. Isso faz com que o carregador do sistema loque esses objetos compartilhados para que o linker de tempo de execução possa usar suas definições. Se a opção -brtl não for usada, um objeto compartilhado que não é referenciado pelo programa não é listado, mesmo que ele forneça definições que possam ser necessárias por outro objeto compartilhado usado pelo programa.
- Um objeto compartilhado contido em um arquivo só é listado se o arquivo especificar carregamento automático para o membro do objeto compartilhado. Especifique o carregamento automático para um membro de archive foo.o criando um arquivo com as seguintes linhas:
e adicionando o arquivo como membro ao arquivo.# autoload #! (foo.o) - No modo dinâmico, os arquivos de entrada especificados com a sinalização -l podem terminar em .so, assim como em .a. Ou seja, uma referência a -lfoo é satisfeita pelo primeiro libfoo.so ou libfoo.a localizado em qualquer um dos diretórios que está sendo procurado. O modo dinâmico está em efeito por padrão, a menos que a opção -bstatic seja usada.
O linker de tempo de execução imita o comportamento do comando ld quando a vinculação estática é usada, exceto que somente símbolos exportados podem ser usados para resolver símbolos. Mesmo quando o link de tempo de execução é usado, o carregador do sistema deve ser capaz de carregar e resolver todas as referências de símbolo no programa principal e em qualquer módulo ele depende. Portanto, se uma definição for removida de um módulo, e o programa principal tiver uma referência a esta definição, o programa não executará, mesmo que outra definição para o símbolo exista em outro módulo.
O Linker de tempo de execução pode rebachar todas as referências a símbolos importados de outro módulo. Uma referência a um símbolo definido no mesmo módulo que a referência só pode ser religada se o módulo foi construído com link de tempo de execução ativado para esse símbolo.
Os módulos compartilhados enviados com o AIX 4.2 ou posterior têm a vinculação em tempo de execução ativada para a maioria das variáveis exportadas. a vinculação de tempo de execução para funções é ativada apenas para funções chamadas por meio de um ponteiro de função. Por exemplo, conforme fornecido, chamadas para a sub-rotina malloc dentro do objeto compartilhado shr.o em /lib/libc.a não podem ser religadas, mesmo se uma definição de malloc existir no programa principal ou em outro módulo compartilhado. Você pode vincular a maioria dos módulos compartilhados enviados para ativar a vinculação de tempo de execução para funções, assim como variáveis executando o comando rtl_enable .
Operação do Linker de tempo de execução
O programa principal é carregado e resolvido pelo carregador do sistema da forma usual. Se o programa executável não puder ser carregado por qualquer motivo, a subroutine exec () falhar e o linker de tempo de execução não for invocado em nada. Se o programa principal carrega com sucesso, o controle passa para o linker de tempo de execução, que religa símbolos conforme descrito a seguir. Quando o linker de tempo de execução é concluído, as rotinas de inicialização são chamadas, se apropriadas, e então a função principal é chamada.
O tempo de execução do linker processa módulos em amplitude-primeira ordem de busca, iniciando-se com o executável principal e continuando com os dependentes diretos do executável principal, de acordo com a ordem dos módulos dependentes listados na seção de carregadores de cada módulo. Esta ordem também é usada ao procurar a instância de definição de um símbolo. A "instância de definição" de um símbolo é geralmente a primeira instância de um símbolo, mas há duas exceções. Se a primeira instância de um símbolo é uma importação não resolvida, diferida, nenhuma instância de definição existe. Se a primeira instância for um símbolo BSS (ou seja, com o tipo XTY_CM, indicando uma variável não inicializada), e houver outra instância do símbolo que não é um símbolo BSS nem uma importação não resolvida, diferida, a primeira instância dessa instância do símbolo é a instância definindo.
A seção de carregadores de cada módulo lista símbolos importados, que geralmente são definidos em outro módulo especificado, e exportados símbolos, que geralmente são definidos no próprio módulo. Um símbolo que é importado e exportado é chamado de importação "passed-through '". Tal símbolo parece ser definido em um módulo, embora ele seja realmente definido em outro módulo.
Símbolos também podem ser marcados como "importações adiadas". As referências a símbolos de importação adiados nunca são religadas pelo linker de tempo de execução. A resolução desses símbolos deve ser realizada pelo carregador do sistema, seja ligando para loadbind () ou carregando um novo módulo explicitamente com load () ou dlopen ().
As referências aos símbolos importados (exceto as importações adiadas) podem ser sempre religadas. O carregador do sistema já terá resolvido a maioria das importações. As referências a cada símbolo importado são religadas à instância de definição do símbolo. Se nenhuma instância de definição existir, uma mensagem de erro será impressa para erro padrão. Além disso, se a sequência de hash de digitação de um símbolo importado não corresponder à cadeia de hash do símbolo definindo, uma mensagem de erro será impressa.
As referências aos símbolos exportados também são religadas às suas instâncias de definição, desde que as referências apareçam na tabela de realocação da seção de carregadores. (As Importações passadas são processadas juntamente com outras importações, conforme descrito acima.) Dependendo de como o módulo foi vinculado, algumas referências a símbolos exportados são ligadas no horário do link e não podem ser religadas. Uma vez que os símbolos exportados são definidos no módulo de exportação, uma instância de definição do símbolo sempre existirá, a menos que a primeira instância seja uma importação adiada, portanto, os erros são improváveis, mas ainda possíveis, quando a religação exporta símbolos. Tal como acontece com as importações, os erros são impressos se as cordas de hash de digitação não coincidem quando um símbolo é religado.
Sempre que um símbolo é religado, uma dependência é adicionada do módulo usando o símbolo para o módulo definindo o símbolo. Esta dependência impede que os módulos sejam removidos do espaço de endereço prematuramente. Isso é importante quando um módulo carregado pela subroutine dlopen define um símbolo que ainda está sendo usado quando uma tentativa é feita para descarregar o módulo com a subroutine dlclose .
A tabela símbolo da seção do carregador não contém nenhuma informação sobre o alinhamento ou comprimento dos símbolos. Assim, nenhum erro é detectado quando os símbolos são religados a instâncias que são muito curtas ou alinhadas indevidamente. Erros de execução podem ocorrer neste caso.
Uma vez que todos os módulos foram processados, o linker de tempo de execução chama a subroutine exit se qualquer erro de execução de tempo de execução ocorreu, passando um código de saída de144(0x90). Caso contrário, a execução continua chamando rotinas de inicialização ou main ().
Criando um objeto compartilhado com link de tempo de execução ativado
Para criar um objeto compartilhado ativado para vinculação de tempo de execução, você vincula-se com a bandeira -G . Quando esta bandeira é usada, acontecem as seguintes ações:
- Os símbolos exportados recebem onosymbolicatributo, de modo que todas as referências aos símbolos podem ser religadas pelo Linker de tempo de execução.
- São permitidos símbolos indefinidos (veja a opção -berok ). Tais símbolos são marcados como sendo importados a partir do nome do módulo simbólico "..". Símbolos importados de ".." deve ser resolvida pelo linker de tempo de execução antes que eles possam ser usados porque o carregador do sistema não resolverá esses símbolos.
- O arquivo de saída é dado um tipo de módulo deSREcomo se a opção -bM:SRE tivesse sido especificada.
- Todos os objetos compartilhados listados na linha de comando são listados como dependentes do módulo de saída, da mesma maneira como descrito ao vincular um programa com a opção -brtl .
- Os objetos compartilhados em arquivos são listados se tiverem oautoloadatributo.
A utilização da opção -berok , implícita pela sinalização -G , pode mascarar erros que poderiam ser detectados no momento do link. Se você pretende definir todos os símbolos referenciados ao vincular um módulo, você deve usar a opção -bernotok após a sinalização -G . Isso faz com que erros sejam relatados para símbolos indefinidos.