How to display the symbol's type like the nm command?
Asked Answered
H

2

9

I'm studying the ELF format right now. I have to code a simple nm fonction (without the options). I'm already printing on the output the symbol's value and the symbol's name.

Here's the nm output :

value             type    name
0000000000600e30  D       __DTOR_END__

I have the same one, but without the 'type'. I am using the ELF64_Sym structure, as follow :

typedef struct {
    Elf64_Word      st_name;
    unsigned char   st_info;
    unsigned char   st_other;
    Elf64_Half      st_shndx;
    Elf64_Addr      st_value;
    Elf64_Xword     st_size; 
} Elf64_Sym;

I know that I have to use the st_info variable and this macro :

#define ELF64_ST_TYPE(info)          ((info) & 0xf)

to get the symbol's type. But, the symbol type can be a macro as follow :

NAME            VALUE
STT_NOTYPE      0
STT_OBJECT      1
STT_FUNC        2
STT_SECTION     3
STT_FILE        4
STT_LOPROC      13
STT_HIOPROC     15

And I would like to know is how can I get from these macros the letters printed by nm, example:

 U, u, A, a, T, t, R, r, W, w
Headroom answered 5/3, 2013 at 13:44 Comment(2)
A switch statement, perhaps?Lenis
Take this man into account man nm(1): linux.die.net/man/1/nmExurbia
H
10

Ok I did some researchs and here's my function to get the correct character depending on the symbol. Feel free to add / edit some characters.

char            print_type(Elf64_Sym sym, Elf64_Shdr *shdr)
{
  char  c;

  if (ELF64_ST_BIND(sym.st_info) == STB_GNU_UNIQUE)
    c = 'u';
  else if (ELF64_ST_BIND(sym.st_info) == STB_WEAK)
    {
      c = 'W';
      if (sym.st_shndx == SHN_UNDEF)
        c = 'w';
    }
  else if (ELF64_ST_BIND(sym.st_info) == STB_WEAK && ELF64_ST_TYPE(sym.st_info) == STT_OBJECT)
    {
      c = 'V';
      if (sym.st_shndx == SHN_UNDEF)
        c = 'v';
    }
  else if (sym.st_shndx == SHN_UNDEF)
    c = 'U';
  else if (sym.st_shndx == SHN_ABS)
    c = 'A';
  else if (sym.st_shndx == SHN_COMMON)
    c = 'C';
  else if (shdr[sym.st_shndx].sh_type == SHT_NOBITS
       && shdr[sym.st_shndx].sh_flags == (SHF_ALLOC | SHF_WRITE))
    c = 'B';
  else if (shdr[sym.st_shndx].sh_type == SHT_PROGBITS
       && shdr[sym.st_shndx].sh_flags == SHF_ALLOC)
    c = 'R';
  else if (shdr[sym.st_shndx].sh_type == SHT_PROGBITS
       && shdr[sym.st_shndx].sh_flags == (SHF_ALLOC | SHF_WRITE))
    c = 'D';
  else if (shdr[sym.st_shndx].sh_type == SHT_PROGBITS
       && shdr[sym.st_shndx].sh_flags == (SHF_ALLOC | SHF_EXECINSTR))
    c = 'T';
  else if (shdr[sym.st_shndx].sh_type == SHT_DYNAMIC)
    c = 'D';
  else
    c = '?';
  if (ELF64_ST_BIND(sym.st_info) == STB_LOCAL && c != '?')
    c += 32;
  return c;
}

I'm missing the s, n, p and i. I'm quite sure the 'R' is not good. I'll will edit this when I find it.

Headroom answered 7/3, 2013 at 9:42 Comment(0)
A
5

The ELF64_ST_TYPE does not map directly into the letters that nm prints.

In order to perform the mapping, you need to pay attention to both ELF64_ST_BIND, and the section that the symbol refers to. For example:

bool weak = (ELF64_ST_BIND(sym) == STB_WEAK);
bool unresolved = (sym->st_shndx == SHN_UNDEF);

if (unresolved) {
   printf(" %c ", weak ? 'w' : 'U');
}

For t vs T, you'll want to look at ELF64_ST_BIND(sym) == STB_LOCAL or ELF64_ST_BIND(sym) == STB_GLOBAL, and you'll want to find out whether the section referenced by st_shndx is a "text" one (has SHF_EXECINSTR in its flags).

P.S. As far as I know, there is no u. If your nm man page does list u, I am curious to know what type of symbol that is.

Austerity answered 5/3, 2013 at 16:7 Comment(2)
Thank you, this is what I needed to do. I'm using the ELF64_ST_BIND macro to find out if the symbol is local ou global (MIN or MAJ) and then with the section type and section flags I get some characters such as, B, D, T. But there is still more characters to find ! I will continue and post all the results. Here's the nm man with all the characters: linux.die.net/man/1/nmDunstable
@JérémieCharrier Ah, I forgot: u is ELF64_ST_BIND(sym) == STB_GNU_UNIQUE.Austerity

© 2022 - 2024 — McMap. All rights reserved.