elf: declare alignment, move global symbols to end of symtab
This commit is contained in:
parent
d95fa7e564
commit
082a1d4f9f
92
compile.go
92
compile.go
@ -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
18
elf.go
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user