I think it might not be valid, on a technicality
that depends a bit on how you read the gABI.
This object does in fact have a dynamic symbol table:
% elfdump -c foo
Section Header[2]: sh_name: .hash
sh_addr: 0xe8 sh_flags: [ SHF_ALLOC ]
sh_size: 0xc sh_type: [ SHT_HASH ]
sh_offset: 0xe8 sh_entsize: 0x4 (3 entries)
sh_link: 3 sh_info: 0
sh_addralign: 0x4
Section Header[3]: sh_name: .dynsym
sh_addr: 0xf4 sh_flags: [ SHF_ALLOC ]
sh_size: 0 sh_type: [ SHT_DYNSYM ]
sh_offset: 0xf4 sh_entsize: 0x10 (0 entries)
sh_link: 4 sh_info: 1
sh_addralign: 0x4
Section Header[4]: sh_name: .dynstr
sh_addr: 0xf4 sh_flags: [ SHF_ALLOC ]
sh_size: 0x1 sh_type: [ SHT_STRTAB ]
sh_offset: 0xf4 sh_entsize: 0
sh_link: 0 sh_info: 0
sh_addralign: 0x1
The .dynsym has size 0. Its related string table has size 1, which
is the expected NULL byte always found at the front of
a string table, so it's essentially empty also. I think the
problem here is that symbol tables are expected to always have a
zeroed first element, and that's missing here. The gABI says:
Symbol Table
An object file’s symbol table holds information needed to locate
and relocate a program’s symbolic definitions and references. A
symbol table index is a subscript into this array. Index 0 both
designates the first entry in the table and serves as the undefined
symbol index. The contents of the initial entry are specified later
in this section.
One could quibble about whether these words require a 0th element, or
whether it simply defined what has to be there if one is present.
Our implementation, which has roots in the original ATT code does assume
that it's required, and elfdump issues warnings:
% elfdump -h foo
foo: .dynsym: zero sh_size information
foo: .hash: sh_link: 3: does not point to a valid symbol table
I presume that this object has a .dynsym for the benefit of
the hash table. If you didn't have .hash, and didn't issue
DT_HASH in the dynamic section, I think it would be valid not
to have the symbol table. Whether or not it's valid, I think
you'll probably find some tools that will be confused if all
three of these sections are not present.
The other way forward is to ensure that your .dynsym always has
a zeroth element, even if it's otherwise empty. I think that
would be my choice, since it's easy to do, requires no one else
to get involved, and seems to implement the intent of the gABI.
Although this object is self contained, it is a dynamic object
(has program headers, is managed by a runtime linker), so it would
satisfy expectations for it to provide them.
- Ali