mirror of
https://github.com/rui314/mold.git
synced 2024-10-04 08:37:28 +03:00
[elf] Align .symtab's ELF attributes with .dynsym's.
Notably, we previously wrote symbols that have been demoted into STB_LOCAL as STB_GLOBAL. Fix this by using a logic shared with dynsym to determine the output attributes. Also reorder the symbols since the LOCAL ones need to come first. Found in Mesa test suite. Signed-off-by: Tatsuyuki Ishi <ishitatsuyuki@gmail.com>
This commit is contained in:
parent
b19599f81d
commit
536e0e7dca
@ -1235,7 +1235,12 @@ void ObjectFile<E>::compute_symtab(Context<E> &ctx) {
|
||||
if (sym.file == this && is_alive(sym) &&
|
||||
(!ctx.arg.retain_symbols_file || sym.write_to_symtab)) {
|
||||
this->strtab_size += sym.name().size() + 1;
|
||||
this->num_global_symtab++;
|
||||
// Global symbols can be demoted to local symbols based on visibility,
|
||||
// version scripts etc.
|
||||
if (sym.is_local())
|
||||
this->num_local_symtab++;
|
||||
else
|
||||
this->num_global_symtab++;
|
||||
sym.write_to_symtab = true;
|
||||
}
|
||||
}
|
||||
@ -1244,47 +1249,35 @@ void ObjectFile<E>::compute_symtab(Context<E> &ctx) {
|
||||
template <typename E>
|
||||
void ObjectFile<E>::write_symtab(Context<E> &ctx) {
|
||||
ElfSym<E> *symtab_base = (ElfSym<E> *)(ctx.buf + ctx.symtab->shdr.sh_offset);
|
||||
i64 symtab_idx;
|
||||
|
||||
u8 *strtab_base = ctx.buf + ctx.strtab->shdr.sh_offset;
|
||||
i64 strtab_off = this->strtab_offset;
|
||||
|
||||
auto write_sym = [&](Symbol<E> &sym) {
|
||||
auto write_sym = [&](Symbol<E> &sym, i64 &symtab_idx) {
|
||||
ElfSym<E> &esym = symtab_base[symtab_idx++];
|
||||
|
||||
esym = sym.esym();
|
||||
esym.st_name = strtab_off;
|
||||
|
||||
if (sym.get_type() == STT_TLS)
|
||||
esym.st_value = sym.get_addr(ctx, false) - ctx.tls_begin;
|
||||
else
|
||||
esym.st_value = sym.get_addr(ctx, false);
|
||||
|
||||
if (InputSection<E> *isec = sym.get_input_section())
|
||||
esym.st_shndx = isec->output_section->shndx;
|
||||
else if (sym.shndx < 0)
|
||||
esym.st_shndx = -sym.shndx;
|
||||
else if (esym.is_undef())
|
||||
esym.st_shndx = SHN_UNDEF;
|
||||
else
|
||||
esym.st_shndx = SHN_ABS;
|
||||
get_output_esym(ctx, sym, strtab_off, esym);
|
||||
|
||||
write_string(strtab_base + strtab_off, sym.name());
|
||||
strtab_off += sym.name().size() + 1;
|
||||
};
|
||||
|
||||
symtab_idx = this->local_symtab_idx;
|
||||
i64 local_symtab_idx = this->local_symtab_idx;
|
||||
i64 global_symtab_idx = this->global_symtab_idx;
|
||||
for (i64 i = 1; i < this->first_global; i++) {
|
||||
Symbol<E> &sym = *this->symbols[i];
|
||||
if (sym.write_to_symtab)
|
||||
write_sym(sym);
|
||||
write_sym(sym, local_symtab_idx);
|
||||
}
|
||||
|
||||
symtab_idx = this->global_symtab_idx;
|
||||
for (i64 i = this->first_global; i < this->elf_syms.size(); i++) {
|
||||
Symbol<E> &sym = *this->symbols[i];
|
||||
if (sym.file == this && sym.write_to_symtab)
|
||||
write_sym(sym);
|
||||
if (sym.file == this && sym.write_to_symtab) {
|
||||
if (sym.is_local())
|
||||
write_sym(sym, local_symtab_idx);
|
||||
else
|
||||
write_sym(sym, global_symtab_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ this_is_global:
|
||||
module_local:
|
||||
EOF
|
||||
|
||||
echo '{ local: module_local; };' > $t/c.map
|
||||
echo '{ local: module_local; global: *; };' > $t/c.map
|
||||
|
||||
./mold -o $t/exe $t/a.o $t/b.o --version-script=$t/c.map
|
||||
|
||||
@ -37,9 +37,9 @@ readelf --symbols $t/exe > $t/log
|
||||
|
||||
grep -Eq '0 NOTYPE LOCAL DEFAULT .* local1' $t/log
|
||||
grep -Eq '0 NOTYPE LOCAL DEFAULT .* local2' $t/log
|
||||
grep -Eq '0 NOTYPE LOCAL DEFAULT .* module_local' $t/log
|
||||
grep -Eq '0 NOTYPE GLOBAL DEFAULT .* foo' $t/log
|
||||
grep -Eq '0 NOTYPE GLOBAL DEFAULT .* bar' $t/log
|
||||
grep -Eq '0 NOTYPE GLOBAL DEFAULT .* this_is_global' $t/log
|
||||
grep -Eq '0 NOTYPE GLOBAL DEFAULT .* module_local' $t/log
|
||||
|
||||
echo OK
|
||||
|
Loading…
Reference in New Issue
Block a user