work on elf output (2)
This commit is contained in:
parent
e03434bd50
commit
d95fa7e564
183
compile.go
183
compile.go
@ -16,7 +16,9 @@ type section struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type symtabEntry struct {
|
type symtabEntry struct {
|
||||||
symtabSectionIndex int
|
// The index of this symbol within the whole symtab
|
||||||
|
symtabSectionIndex int
|
||||||
|
name_shstrtabOffset int
|
||||||
|
|
||||||
sectionName string
|
sectionName string
|
||||||
kind string
|
kind string
|
||||||
@ -41,55 +43,79 @@ func NewCompiler() *compiler {
|
|||||||
// First, there's an all-zero entry that is reserved for extended ELF headers
|
// First, there's an all-zero entry that is reserved for extended ELF headers
|
||||||
c.sections = append(c.sections, section{})
|
c.sections = append(c.sections, section{})
|
||||||
|
|
||||||
|
// Real entry: shstrtab
|
||||||
c.sections = append(c.sections, section{
|
c.sections = append(c.sections, section{
|
||||||
name: `.shstrtab`, // Mandatory: the table that names sections themselves
|
name: `.shstrtab`, // Mandatory: the table that names sections themselves
|
||||||
name_shstrtabOffset: 1,
|
buff: &bytes.Buffer{},
|
||||||
buff: &bytes.Buffer{},
|
|
||||||
})
|
})
|
||||||
c.shstrtab = &c.sections[1]
|
c.shstrtab = &c.sections[1]
|
||||||
|
|
||||||
// The first byte in a string table is conventionally expected be \x00, so that you can reference
|
// The first byte in a string table is conventionally expected be \x00, so that you can reference
|
||||||
// null strings with it
|
// null strings with it
|
||||||
c.shstrtab.buff.WriteByte(0)
|
c.StringTable("")
|
||||||
|
|
||||||
c.shstrtab.buff.WriteString(c.shstrtab.name)
|
c.shstrtab.name_shstrtabOffset = c.StringTable(c.shstrtab.name)
|
||||||
c.shstrtab.buff.WriteByte(0)
|
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *compiler) StringTable(text string) int {
|
||||||
|
pos := c.shstrtab.buff.Len()
|
||||||
|
|
||||||
|
c.shstrtab.buff.WriteString(text)
|
||||||
|
c.shstrtab.buff.WriteByte(0)
|
||||||
|
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
|
||||||
func (c *compiler) CreateSymbol(name string, class string, offset int64, length int64, global bool) error {
|
func (c *compiler) CreateSymbol(name string, class string, offset int64, length int64, global bool) error {
|
||||||
|
|
||||||
if _, ok := c.symtab[name]; ok {
|
if _, ok := c.symtab[name]; ok {
|
||||||
return fmt.Errorf("Symbol %q already exists", name)
|
return fmt.Errorf("Symbol %q already exists", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fmt.Printf("--> CreateSymbol(%s)\n", name)
|
||||||
|
|
||||||
// Find the .symtab section, or create if it does not exist
|
// Find the .symtab section, or create if it does not exist
|
||||||
symtabSec := c.FindOrCreateSection(`.symtab`)
|
symtabSec := c.FindOrCreateSection(`.symtab`)
|
||||||
|
if symtabSec.buff.Len() == 0 {
|
||||||
|
// First time initialized
|
||||||
|
|
||||||
|
// Add a zeroth symtab entry - zero is a sentinel, not a usable entry
|
||||||
|
symtabSec.buff.Write(make([]byte, 8*3))
|
||||||
|
}
|
||||||
|
|
||||||
// New entry index = length / len(entry) = length / 24
|
// New entry index = length / len(entry) = length / 24
|
||||||
nextIndex := symtabSec.buff.Len() / 24
|
nextIndex := symtabSec.buff.Len() / 24
|
||||||
|
|
||||||
// Add to our fast lookup table
|
// Add to our fast lookup table
|
||||||
c.symtab[name] = symtabEntry{
|
ste := symtabEntry{
|
||||||
symtabSectionIndex: nextIndex,
|
symtabSectionIndex: nextIndex,
|
||||||
|
kind: class,
|
||||||
sectionName: c.currentSection.name,
|
offset: offset,
|
||||||
kind: class,
|
global: global,
|
||||||
offset: offset,
|
length: length,
|
||||||
global: global,
|
|
||||||
length: length,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the section index for the section containing this symbol
|
// Find the section index for the section containing this symbol
|
||||||
sectionIndex := -1
|
var srcSectionIdx int = 0
|
||||||
for i, _ := range c.sections {
|
var sttType uint8 = STT_NOTYPE
|
||||||
if c.sections[i].name == c.currentSection.name {
|
|
||||||
sectionIndex = i
|
if class == `.section` {
|
||||||
break
|
ste.sectionName = name
|
||||||
|
srcSectionIdx = len(c.sections) - 1 // The most recent added section
|
||||||
|
sttType = STT_SECTION
|
||||||
|
|
||||||
|
} else if c.currentSection != nil {
|
||||||
|
ste.sectionName = c.currentSection.name
|
||||||
|
var ok bool
|
||||||
|
srcSectionIdx, ok = c.FindSectionIndex(c.currentSection.name)
|
||||||
|
if !ok {
|
||||||
|
panic("current section does not exist?")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if sectionIndex == -1 {
|
} else {
|
||||||
return fmt.Errorf("Current section missing index")
|
panic("Symbol is neither a section, nor within a section (?)")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to the .symtab section
|
// Add to the .symtab section
|
||||||
@ -97,14 +123,42 @@ func (c *compiler) CreateSymbol(name string, class string, offset int64, length
|
|||||||
// created, linking it with any other .o files will create a combined .text
|
// created, linking it with any other .o files will create a combined .text
|
||||||
// section where all the offsets have shifted
|
// section where all the offsets have shifted
|
||||||
esym := Elf64_Sym{}
|
esym := Elf64_Sym{}
|
||||||
esym.st_name = 0 // Default: unnamed
|
|
||||||
esym.st_info = STT_SECTION | (STB_LOCAL << 4)
|
if class == `.section` {
|
||||||
esym.st_other = STV_HIDDEN // For this translation unit only
|
esym.st_name = uint32(c.StringTable(name)) // Write name into public string table
|
||||||
esym.st_shndx = uint16(sectionIndex)
|
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)
|
||||||
|
|
||||||
|
} 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stash in symtabEntry
|
||||||
|
ste.name_shstrtabOffset = int(esym.st_name)
|
||||||
|
c.symtab[name] = ste
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compiler) Must(b []byte) {
|
func (c *compiler) Must(b []byte) {
|
||||||
@ -149,18 +203,24 @@ func (c *compiler) FindOrCreateSection(sectionName string) *section {
|
|||||||
|
|
||||||
// No section with this name. Create it
|
// No section with this name. Create it
|
||||||
c.sections = append(c.sections, section{
|
c.sections = append(c.sections, section{
|
||||||
name: sectionName,
|
name: sectionName,
|
||||||
name_shstrtabOffset: c.shstrtab.buff.Len(),
|
buff: &bytes.Buffer{},
|
||||||
buff: &bytes.Buffer{},
|
|
||||||
})
|
})
|
||||||
|
sec := &c.sections[len(c.sections)-1]
|
||||||
|
|
||||||
c.shstrtab.buff.WriteString(sectionName)
|
// Create a symbol for it
|
||||||
c.shstrtab.buff.WriteByte(0)
|
// This creates a string table entry for us
|
||||||
|
err := c.CreateSymbol(sectionName, ".section", 0, 0, true)
|
||||||
|
if err != nil {
|
||||||
|
panic("CreateSymbol: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
return &c.sections[len(c.sections)-1]
|
sec.name_shstrtabOffset = c.StringTable(sectionName)
|
||||||
|
|
||||||
|
return sec
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compiler) Reloc(symbolName string, mode ElfRelocationType, addOffset int64) error {
|
func (c *compiler) Reloc(symbolName string, mode ElfRelocationType) error {
|
||||||
// Find '.rela.{currentsection}', creating it if it does not exist
|
// Find '.rela.{currentsection}', creating it if it does not exist
|
||||||
var relaSec *section = c.FindOrCreateSection(`.rela` + c.currentSection.name)
|
var relaSec *section = c.FindOrCreateSection(`.rela` + c.currentSection.name)
|
||||||
|
|
||||||
@ -170,11 +230,19 @@ func (c *compiler) Reloc(symbolName string, mode ElfRelocationType, addOffset in
|
|||||||
return fmt.Errorf("Reference to unknown symbol %q", symbolName)
|
return fmt.Errorf("Reference to unknown symbol %q", symbolName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find the symbol pointing to its parent section
|
||||||
|
parentSectionSyminfo, ok := c.symtab[syminfo.sectionName]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Bad parent section")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("-->Relocation %q found in %q (sectionidx %d)\n", symbolName, syminfo.sectionName, parentSectionSyminfo.symtabSectionIndex)
|
||||||
|
|
||||||
// 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(syminfo.symtabSectionIndex)<<32 | uint64(mode) // high bits: Index of search symbol in the symtab. 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 = addOffset
|
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 {
|
||||||
@ -235,7 +303,7 @@ func (c *compiler) Compile(t Token) error {
|
|||||||
return fmt.Errorf("variable %q has unknown size class %q", tok.VarName, tok.Sizeclass)
|
return fmt.Errorf("variable %q has unknown size class %q", tok.VarName, tok.Sizeclass)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := c.CreateSymbol(tok.VarName, ".var."+tok.Sizeclass, int64(c.currentSection.buff.Len()), position-int64(c.currentSection.buff.Len()), false)
|
err := c.CreateSymbol(tok.VarName, ".var."+tok.Sizeclass, int64(position), int64(c.currentSection.buff.Len())-position, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -293,7 +361,7 @@ func (c *compiler) Compile(t Token) error {
|
|||||||
panic("mov $var,rax pattern: missing case")
|
panic("mov $var,rax pattern: missing case")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.Reloc(tok.Args[0][1:], R_X86_64_32S, 0) // Declare that this is a 32-bit reloc, not a 64-bit one
|
err = c.Reloc(tok.Args[0][1:], R_X86_64_32S) // Declare that this is a 32-bit reloc, not a 64-bit one
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("mov with relocation: %w", err)
|
return fmt.Errorf("mov with relocation: %w", err)
|
||||||
}
|
}
|
||||||
@ -313,7 +381,7 @@ func (c *compiler) Compile(t Token) error {
|
|||||||
panic("mov rxx,$var pattern: missing case")
|
panic("mov rxx,$var pattern: missing case")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.Reloc(tok.Args[1][1:], R_X86_64_32S, 0) // Declare that this is a 32-bit reloc, not a 64-bit one
|
err = c.Reloc(tok.Args[1][1:], R_X86_64_32S) // Declare that this is a 32-bit reloc, not a 64-bit one
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("mov with relocation: %w", err)
|
return fmt.Errorf("mov with relocation: %w", err)
|
||||||
}
|
}
|
||||||
@ -339,7 +407,7 @@ func (c *compiler) Compile(t Token) error {
|
|||||||
panic("mov $var,rxx pattern: missing case")
|
panic("mov $var,rxx pattern: missing case")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.Reloc(tok.Args[1][2:], R_X86_64_64, 0)
|
err = c.Reloc(tok.Args[1][2:], R_X86_64_64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("mov with relocation: %w", err)
|
return fmt.Errorf("mov with relocation: %w", err)
|
||||||
}
|
}
|
||||||
@ -428,33 +496,38 @@ 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
|
||||||
// Default (unknown section):
|
|
||||||
// Treat as extra read-only data (.rodata)
|
|
||||||
shdr.sh_type = 1 // SHT_PROGBITS, program data
|
|
||||||
shdr.sh_flags = 0x10 // MERGE
|
|
||||||
|
|
||||||
switch sec.name {
|
switch sec.name {
|
||||||
case ".text":
|
case ".text":
|
||||||
shdr.sh_type = SHT_PROGBITS
|
shdr.sh_type = SHT_PROGBITS
|
||||||
shdr.sh_flags = 0x2 | 0x4 | 0x10 // WRITE|ALLOC|MERGE
|
shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR
|
||||||
|
|
||||||
case ".data":
|
case ".data":
|
||||||
shdr.sh_type = SHT_PROGBITS
|
shdr.sh_type = SHT_PROGBITS
|
||||||
shdr.sh_flags = 0x2 | 0x10 // WRITE|MERGE
|
shdr.sh_flags = SHF_WRITE | SHF_ALLOC
|
||||||
|
|
||||||
case ".symtab":
|
case ".symtab":
|
||||||
shdr.sh_type = SHT_SYMTAB
|
shdr.sh_type = SHT_SYMTAB
|
||||||
shdr.sh_flags = 0x10 | 0x20 // MERGE|STRINGS
|
shdr.sh_flags = 0
|
||||||
shdr.sh_info = uint32(len(c.symtab))
|
shdr.sh_info = uint32(len(c.symtab) + 1)
|
||||||
shdr.sh_entsize = uint64(sec.buff.Len()) // Number of fixed-sized symtab entries
|
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(!?!)
|
||||||
|
|
||||||
case ".shstrtab":
|
case ".shstrtab":
|
||||||
shdr.sh_type = SHT_STRTAB
|
shdr.sh_type = SHT_STRTAB
|
||||||
shdr.sh_flags = 0x10 | 0x20 // MERGE|STRINGS
|
shdr.sh_flags = 0
|
||||||
|
|
||||||
|
case ".rodata":
|
||||||
|
shdr.sh_type = SHT_PROGBITS
|
||||||
|
shdr.sh_flags = SHF_ALLOC
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if strings.HasPrefix(sec.name, ".rela.") {
|
if strings.HasPrefix(sec.name, ".rela.") {
|
||||||
shdr.sh_type = SHT_RELA
|
shdr.sh_type = SHT_RELA
|
||||||
shdr.sh_flags = 0 // ?
|
shdr.sh_flags = 0 // ?
|
||||||
shdr.sh_link = uint32(symtabSectionIndex) // The index of the symtab section
|
shdr.sh_link = uint32(symtabSectionIndex)
|
||||||
|
shdr.sh_entsize = 24 // Size in bytes of each entry
|
||||||
|
|
||||||
// Find the index of the section for which this relocates. Match by name
|
// Find the index of the section for which this relocates. Match by name
|
||||||
srcSectionIdx, ok := c.FindSectionIndex(sec.name[5:])
|
srcSectionIdx, ok := c.FindSectionIndex(sec.name[5:])
|
||||||
@ -462,6 +535,8 @@ 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)
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("don't know the right flags to use for section %q", sec.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
11
elf.go
11
elf.go
@ -57,6 +57,17 @@ const (
|
|||||||
SHT_PREINIT_ARRAY = 16
|
SHT_PREINIT_ARRAY = 16
|
||||||
SHT_GROUP = 17
|
SHT_GROUP = 17
|
||||||
SHT_SYMTAB_SHNDX = 18
|
SHT_SYMTAB_SHNDX = 18
|
||||||
|
|
||||||
|
SHF_WRITE = 0x1
|
||||||
|
SHF_ALLOC = 0x2
|
||||||
|
SHF_EXECINSTR = 0x4
|
||||||
|
SHF_MERGE = 0x10
|
||||||
|
SHF_STRINGS = 0x20
|
||||||
|
SHF_INFO_LINK = 0x40
|
||||||
|
SHF_LINK_ORDER = 0x80
|
||||||
|
SHF_OS_NONCONFORMING = 0x100
|
||||||
|
SHF_GROUP = 0x200
|
||||||
|
SHF_TLS = 0x400
|
||||||
)
|
)
|
||||||
|
|
||||||
// Elf64_Shdr is the Section header
|
// Elf64_Shdr is the Section header
|
||||||
|
Loading…
Reference in New Issue
Block a user