elf: declare alignment, move global symbols to end of symtab

This commit is contained in:
mappu 2023-12-11 18:06:35 +13:00
parent d95fa7e564
commit 082a1d4f9f
2 changed files with 78 additions and 32 deletions

View File

@ -125,29 +125,29 @@ func (c *compiler) CreateSymbol(name string, class string, offset int64, length
esym := Elf64_Sym{}
if class == `.section` {
esym.st_name = uint32(c.StringTable(name)) // Write name into public string table
esym.st_info = sttType | (STB_LOCAL << 4)
esym.st_other = STV_DEFAULT
esym.st_shndx = uint16(srcSectionIdx)
esym.St_name = uint32(c.StringTable(name)) // Write name into public string table
esym.St_info = sttType | (STB_LOCAL << 4)
esym.St_other = STV_DEFAULT
esym.St_shndx = uint16(srcSectionIdx)
} else if global {
esym.st_name = uint32(c.StringTable(name)) // Write name into public string table
esym.st_info = sttType | (STB_GLOBAL << 4)
esym.st_other = STV_DEFAULT
esym.st_shndx = uint16(srcSectionIdx)
esym.St_name = uint32(c.StringTable(name)) // Write name into public string table
esym.St_info = sttType | (STB_GLOBAL << 4)
esym.St_other = STV_DEFAULT
esym.St_shndx = uint16(srcSectionIdx)
} else {
// Private variable for this translation unit
// Needs an entry, but no need to expose the name
esym.st_name = 0 // uint32(c.StringTable(name)) // Write name into public string table // 0 // Default: unnamed (0th entry in our string table is \x00)
esym.st_info = sttType | (STB_LOCAL << 4)
esym.st_other = STV_HIDDEN // For this translation unit only
esym.st_shndx = uint16(srcSectionIdx)
esym.St_name = 0 // uint32(c.StringTable(name)) // Write name into public string table // 0 // Default: unnamed (0th entry in our string table is \x00)
esym.St_info = sttType | (STB_LOCAL << 4)
esym.St_other = STV_HIDDEN // For this translation unit only
esym.St_shndx = uint16(srcSectionIdx)
}
fmt.Printf("-->New symbol %q in section %q (sectionidx %v)\n", name, ste.sectionName, srcSectionIdx)
esym.st_size = uint64(length)
esym.St_size = uint64(length)
err := binary.Write(symtabSec.buff, binary.LittleEndian, &esym)
if err != nil {
@ -155,7 +155,7 @@ func (c *compiler) CreateSymbol(name string, class string, offset int64, length
}
// Stash in symtabEntry
ste.name_shstrtabOffset = int(esym.st_name)
ste.name_shstrtabOffset = int(esym.St_name)
c.symtab[name] = ste
return nil
@ -240,9 +240,9 @@ func (c *compiler) Reloc(symbolName string, mode ElfRelocationType) error {
// Add the relocation to the .rela section
rr := Elf64_Rela{}
rr.r_offset = uint64(c.currentSection.buff.Len())
rr.r_info = uint64(parentSectionSyminfo.symtabSectionIndex)<<32 | uint64(mode) // high bits: Index of search symbol in the symtab (the source section). low bits: mode type
rr.r_addend = syminfo.offset // Add to the result when relocating (offset within source section)
rr.R_offset = uint64(c.currentSection.buff.Len())
rr.R_info = uint64(parentSectionSyminfo.symtabSectionIndex)<<32 | uint64(mode) // high bits: Index of search symbol in the symtab (the source section). low bits: mode type
rr.R_addend = syminfo.offset // Add to the result when relocating (offset within source section)
err := binary.Write(relaSec.buff, binary.LittleEndian, &rr)
if err != nil {
@ -455,8 +455,49 @@ func (c *compiler) Compile(t Token) error {
func (c *compiler) Finalize(dest io.Writer) error {
// Find some well-known section indexes
symtabSectionIndex, _ := c.FindSectionIndex(`.symtab`)
shstrtabSectionIndex, _ := c.FindSectionIndex(`.shstrtab`)
symtabSectionIndex, ok := c.FindSectionIndex(`.symtab`)
if !ok {
return fmt.Errorf("No symbol table present")
}
shstrtabSectionIndex, ok := c.FindSectionIndex(`.shstrtab`)
if !ok {
return fmt.Errorf("No string table present")
}
// (Safely) move all global symtab to the end
// Because there may be existing references to global symtab entries (e.g. relocs)
// just duplicate them in place
tmp := c.sections[symtabSectionIndex].buff.Bytes()
extraSymtabContent := bytes.Buffer{}
for i := 0; i < len(tmp); i += 24 {
sym := Elf64_Sym{}
err := binary.Read(bytes.NewReader(tmp[i:i+24]), binary.LittleEndian, &sym)
if err != nil {
return err
}
if sym.St_info&(STB_GLOBAL<<4) == 0 {
continue // not a global symbol
}
// Was a global symbol
// Re-add the global symbol at the end
extraSymtabContent.Write(tmp[i : i+24])
// Patch the existing symbol
sym.St_name = 0
sym.St_info &= ^uint8(STB_GLOBAL << 4)
replacement := bytes.Buffer{}
err = binary.Write(&replacement, binary.LittleEndian, &sym)
if err != nil {
return err
}
copy(tmp[i:i+24], replacement.Bytes())
}
numLocalSymbols := len(tmp) / 24
c.sections[symtabSectionIndex].buff.Write(extraSymtabContent.Bytes())
// Write ELF header
ehdr := Elf64_Ehdr{}
@ -496,31 +537,35 @@ func (c *compiler) Finalize(dest io.Writer) error {
shdr := Elf64_Shdr{}
shdr.sh_name = uint32(sec.name_shstrtabOffset)
shdr.sh_addralign = 1 // Not doing any proper alignment
switch sec.name {
case ".text":
shdr.sh_type = SHT_PROGBITS
shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR
shdr.sh_addralign = 16 // Request for final linking
case ".data":
shdr.sh_type = SHT_PROGBITS
shdr.sh_flags = SHF_WRITE | SHF_ALLOC
shdr.sh_addralign = 4 // Request for final linking
case ".symtab":
shdr.sh_type = SHT_SYMTAB
shdr.sh_flags = 0
shdr.sh_info = uint32(len(c.symtab) + 1)
shdr.sh_entsize = 24 // Size in bytes of each entry
shdr.sh_link = 1 // The index of the section containing the actual strings. We reuse shstrtab(!?!)
shdr.sh_info = uint32(numLocalSymbols) // sh_info points to the first global symbol. Global symbols must go after local symbols
shdr.sh_entsize = 24 // Size in bytes of each entry
shdr.sh_link = 1 // The index of the section containing the actual strings. We reuse shstrtab(!?!)
shdr.sh_addralign = 8 // Request for final linking
case ".shstrtab":
shdr.sh_type = SHT_STRTAB
shdr.sh_flags = 0
shdr.sh_addralign = 1 // Not doing any proper alignment
case ".rodata":
shdr.sh_type = SHT_PROGBITS
shdr.sh_flags = SHF_ALLOC
shdr.sh_addralign = 4 // Request for final linking
default:
if strings.HasPrefix(sec.name, ".rela.") {
@ -535,6 +580,7 @@ func (c *compiler) Finalize(dest io.Writer) error {
return fmt.Errorf("Missing parent section for relocation section %q", sec.name)
}
shdr.sh_info = uint32(srcSectionIdx)
shdr.sh_addralign = 8 // Request for final linking
} else {
return fmt.Errorf("don't know the right flags to use for section %q", sec.name)
}

18
elf.go
View File

@ -105,19 +105,19 @@ const (
// Elf64_Sym is a symbol
type Elf64_Sym struct {
st_name uint32
st_info uint8
st_other uint8
st_shndx uint16
st_value uint64
st_size uint64
St_name uint32
St_info uint8
St_other uint8
St_shndx uint16
St_value uint64
St_size uint64
}
// Elf64_Rela is a relocation with addend
type Elf64_Rela struct {
r_offset uint64
r_info uint64
r_addend int64
R_offset uint64
R_info uint64
R_addend int64
}
// Relocation types