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{}
|
esym := Elf64_Sym{}
|
||||||
|
|
||||||
if class == `.section` {
|
if class == `.section` {
|
||||||
esym.st_name = uint32(c.StringTable(name)) // Write name into public string table
|
esym.St_name = uint32(c.StringTable(name)) // Write name into public string table
|
||||||
esym.st_info = sttType | (STB_LOCAL << 4)
|
esym.St_info = sttType | (STB_LOCAL << 4)
|
||||||
esym.st_other = STV_DEFAULT
|
esym.St_other = STV_DEFAULT
|
||||||
esym.st_shndx = uint16(srcSectionIdx)
|
esym.St_shndx = uint16(srcSectionIdx)
|
||||||
|
|
||||||
} else if global {
|
} else if global {
|
||||||
esym.st_name = uint32(c.StringTable(name)) // Write name into public string table
|
esym.St_name = uint32(c.StringTable(name)) // Write name into public string table
|
||||||
esym.st_info = sttType | (STB_GLOBAL << 4)
|
esym.St_info = sttType | (STB_GLOBAL << 4)
|
||||||
esym.st_other = STV_DEFAULT
|
esym.St_other = STV_DEFAULT
|
||||||
esym.st_shndx = uint16(srcSectionIdx)
|
esym.St_shndx = uint16(srcSectionIdx)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Private variable for this translation unit
|
// Private variable for this translation unit
|
||||||
// Needs an entry, but no need to expose the name
|
// 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_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_info = sttType | (STB_LOCAL << 4)
|
||||||
esym.st_other = STV_HIDDEN // For this translation unit only
|
esym.St_other = STV_HIDDEN // For this translation unit only
|
||||||
esym.st_shndx = uint16(srcSectionIdx)
|
esym.St_shndx = uint16(srcSectionIdx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("-->New symbol %q in section %q (sectionidx %v)\n", name, ste.sectionName, 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)
|
err := binary.Write(symtabSec.buff, binary.LittleEndian, &esym)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -155,7 +155,7 @@ func (c *compiler) CreateSymbol(name string, class string, offset int64, length
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stash in symtabEntry
|
// Stash in symtabEntry
|
||||||
ste.name_shstrtabOffset = int(esym.st_name)
|
ste.name_shstrtabOffset = int(esym.St_name)
|
||||||
c.symtab[name] = ste
|
c.symtab[name] = ste
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -240,9 +240,9 @@ func (c *compiler) Reloc(symbolName string, mode ElfRelocationType) error {
|
|||||||
|
|
||||||
// Add the relocation to the .rela section
|
// Add the relocation to the .rela section
|
||||||
rr := Elf64_Rela{}
|
rr := Elf64_Rela{}
|
||||||
rr.r_offset = uint64(c.currentSection.buff.Len())
|
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_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_addend = syminfo.offset // Add to the result when relocating (offset within source section)
|
||||||
|
|
||||||
err := binary.Write(relaSec.buff, binary.LittleEndian, &rr)
|
err := binary.Write(relaSec.buff, binary.LittleEndian, &rr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -455,8 +455,49 @@ func (c *compiler) Compile(t Token) error {
|
|||||||
func (c *compiler) Finalize(dest io.Writer) error {
|
func (c *compiler) Finalize(dest io.Writer) error {
|
||||||
|
|
||||||
// Find some well-known section indexes
|
// Find some well-known section indexes
|
||||||
symtabSectionIndex, _ := c.FindSectionIndex(`.symtab`)
|
symtabSectionIndex, ok := c.FindSectionIndex(`.symtab`)
|
||||||
shstrtabSectionIndex, _ := c.FindSectionIndex(`.shstrtab`)
|
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
|
// Write ELF header
|
||||||
ehdr := Elf64_Ehdr{}
|
ehdr := Elf64_Ehdr{}
|
||||||
@ -496,31 +537,35 @@ func (c *compiler) Finalize(dest io.Writer) error {
|
|||||||
shdr := Elf64_Shdr{}
|
shdr := Elf64_Shdr{}
|
||||||
|
|
||||||
shdr.sh_name = uint32(sec.name_shstrtabOffset)
|
shdr.sh_name = uint32(sec.name_shstrtabOffset)
|
||||||
shdr.sh_addralign = 1 // Not doing any proper alignment
|
|
||||||
|
|
||||||
switch sec.name {
|
switch sec.name {
|
||||||
case ".text":
|
case ".text":
|
||||||
shdr.sh_type = SHT_PROGBITS
|
shdr.sh_type = SHT_PROGBITS
|
||||||
shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR
|
shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR
|
||||||
|
shdr.sh_addralign = 16 // Request for final linking
|
||||||
|
|
||||||
case ".data":
|
case ".data":
|
||||||
shdr.sh_type = SHT_PROGBITS
|
shdr.sh_type = SHT_PROGBITS
|
||||||
shdr.sh_flags = SHF_WRITE | SHF_ALLOC
|
shdr.sh_flags = SHF_WRITE | SHF_ALLOC
|
||||||
|
shdr.sh_addralign = 4 // Request for final linking
|
||||||
|
|
||||||
case ".symtab":
|
case ".symtab":
|
||||||
shdr.sh_type = SHT_SYMTAB
|
shdr.sh_type = SHT_SYMTAB
|
||||||
shdr.sh_flags = 0
|
shdr.sh_flags = 0
|
||||||
shdr.sh_info = uint32(len(c.symtab) + 1)
|
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_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_link = 1 // The index of the section containing the actual strings. We reuse shstrtab(!?!)
|
||||||
|
shdr.sh_addralign = 8 // Request for final linking
|
||||||
|
|
||||||
case ".shstrtab":
|
case ".shstrtab":
|
||||||
shdr.sh_type = SHT_STRTAB
|
shdr.sh_type = SHT_STRTAB
|
||||||
shdr.sh_flags = 0
|
shdr.sh_flags = 0
|
||||||
|
shdr.sh_addralign = 1 // Not doing any proper alignment
|
||||||
|
|
||||||
case ".rodata":
|
case ".rodata":
|
||||||
shdr.sh_type = SHT_PROGBITS
|
shdr.sh_type = SHT_PROGBITS
|
||||||
shdr.sh_flags = SHF_ALLOC
|
shdr.sh_flags = SHF_ALLOC
|
||||||
|
shdr.sh_addralign = 4 // Request for final linking
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if strings.HasPrefix(sec.name, ".rela.") {
|
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)
|
return fmt.Errorf("Missing parent section for relocation section %q", sec.name)
|
||||||
}
|
}
|
||||||
shdr.sh_info = uint32(srcSectionIdx)
|
shdr.sh_info = uint32(srcSectionIdx)
|
||||||
|
shdr.sh_addralign = 8 // Request for final linking
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("don't know the right flags to use for section %q", sec.name)
|
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
|
// Elf64_Sym is a symbol
|
||||||
type Elf64_Sym struct {
|
type Elf64_Sym struct {
|
||||||
st_name uint32
|
St_name uint32
|
||||||
st_info uint8
|
St_info uint8
|
||||||
st_other uint8
|
St_other uint8
|
||||||
st_shndx uint16
|
St_shndx uint16
|
||||||
st_value uint64
|
St_value uint64
|
||||||
st_size uint64
|
St_size uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// Elf64_Rela is a relocation with addend
|
// Elf64_Rela is a relocation with addend
|
||||||
type Elf64_Rela struct {
|
type Elf64_Rela struct {
|
||||||
r_offset uint64
|
R_offset uint64
|
||||||
r_info uint64
|
R_info uint64
|
||||||
r_addend int64
|
R_addend int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// Relocation types
|
// Relocation types
|
||||||
|
Loading…
Reference in New Issue
Block a user