101 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			V
		
	
	
			
		
		
	
	
			101 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			V
		
	
	
| // Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
 | |
| // Use of this source code is governed by an MIT license
 | |
| // that can be found in the LICENSE file.
 | |
| module x64
 | |
| 
 | |
| import os
 | |
| 
 | |
| const (
 | |
| 	mag0 = 0x7f
 | |
| 	mag1 = `E`
 | |
| 	mag2 = `L`
 | |
| 	mag3 = `F`
 | |
| 	ei_class = 4
 | |
| 	elfclass64 = 2
 | |
| 	elfdata2lsb = 1
 | |
| 	ev_current = 1
 | |
| 	elf_osabi = 0
 | |
| 	// ELF file types
 | |
| 	et_rel = 1
 | |
| 	et_exec = 2
 | |
| 	et_dyn = 3
 | |
| 	e_machine = 0x3e
 | |
| 	shn_xindex = 0xffff
 | |
| 	sht_null = 0
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	segment_start = 0x400000
 | |
| )
 | |
| 
 | |
| pub fn (g mut Gen) generate_elf_header() {
 | |
| 	g.buf << [byte(mag0), mag1, mag2, mag3]
 | |
| 	g.buf << elfclass64 // file class
 | |
| 	g.buf << elfdata2lsb // data encoding
 | |
| 	g.buf << ev_current // file version
 | |
| 	g.buf << 1 // elf_osabi
 | |
| 	g.write64(0) // et_rel) // et_rel for .o
 | |
| 	g.write16(2) // e_type
 | |
| 	g.write16(e_machine) //
 | |
| 	g.write32(ev_current) // e_version
 | |
| 	eh_size := 0x40
 | |
| 	phent_size := 0x38
 | |
| 	g.write64(segment_start + eh_size + phent_size) // e_entry
 | |
| 	g.write64(0x40) // e_phoff
 | |
| 	g.write64(0) // e_shoff
 | |
| 	g.write32(0) // e_flags
 | |
| 	g.write16(eh_size) // e_ehsize
 | |
| 	g.write16(phent_size) // e_phentsize
 | |
| 	g.write16(1) // e_phnum
 | |
| 	g.write16(0) // e_shentsize
 | |
| 	g.write16(0) // e_shnum (number of sections)
 | |
| 	g.write16(0) // e_shstrndx
 | |
| 	// Elf64_Phdr
 | |
| 	g.write32(1) // p_type
 | |
| 	g.write32(5) // p_flags
 | |
| 	g.write64(0) // p_offset
 | |
| 	g.write64(segment_start) // p_vaddr addr:050
 | |
| 	g.write64(segment_start) //
 | |
| 	g.file_size_pos = g.buf.len
 | |
| 	g.write64(0) // p_filesz PLACEHOLDER, set to file_size later // addr: 060
 | |
| 	g.write64(0) // p_memsz
 | |
| 	g.write64(0x1000) // p_align
 | |
| 	// user code starts here at
 | |
| 	// address: 00070 and a half
 | |
| 	g.code_start_pos = g.buf.len
 | |
| 	g.call(0) // call main function, it's not guaranteed to be the first
 | |
| }
 | |
| 
 | |
| pub fn (g mut Gen) generate_elf_footer() {
 | |
| 	// Return 0
 | |
| 	g.mov(.edi, 0) // ret value
 | |
| 	g.mov(.eax, 60)
 | |
| 	g.syscall()
 | |
| 	// Strings table
 | |
| 	// Loop thru all strings and set the right addresses
 | |
| 	for i, s in g.strings {
 | |
| 		g.write64_at(segment_start + g.buf.len, int(g.str_pos[i]))
 | |
| 		g.write_string(s)
 | |
| 		g.write8(6)
 | |
| 	}
 | |
| 	// Now we know the file size, set it
 | |
| 	file_size := g.buf.len
 | |
| 	g.write64_at(file_size, g.file_size_pos) // set file size 64 bit value
 | |
| 	g.write64_at(file_size, g.file_size_pos + 8)
 | |
| 	// call main function, it's not guaranteed to be the first
 | |
| 	// we generated call(0) ("e8 0")
 | |
| 	// no need to replace "0" with a relative address of the main function
 | |
| 	// +1 is for "e8"
 | |
| 	// -5 is for "e8 00 00 00 00"
 | |
| 	g.write64_at(int(g.main_fn_addr - g.code_start_pos) - 5, g.code_start_pos + 1)
 | |
| 	// Create the binary
 | |
| 	mut f := os.create(g.out_name)or{
 | |
| 		panic(err)
 | |
| 	}
 | |
| 	os.chmod(g.out_name, 0775)
 | |
| 	f.write_bytes(g.buf.data, g.buf.len)
 | |
| 	f.close()
 | |
| 	println('x64 elf binary has been successfully generated')
 | |
| }
 | |
| 
 |