1 #include "assembler.hpp"
2 #include "serialization.hpp"
5 #if !defined(_WIN32) && !defined(_WIN64)
15 #define MAP_ANONYMOUS MAP_ANON
21 assembler::assembler()
25 void assembler::_label(label
& l
)
30 void assembler::_label(label
& l
, const std::string
& globalname
)
33 globals
[globalname
] = &l
;
36 void assembler::byte(uint8_t b
)
41 void assembler::byte(std::initializer_list
<uint8_t> b
)
47 void assembler::byte(const uint8_t* b
, size_t l
)
49 for(size_t i
= 0; i
< l
; i
++)
53 void assembler::relocation(std::function
<void(uint8_t* location
, size_t target
, size_t source
)> promise
,
59 r
.source
= data
.size();
63 void assembler::align(size_t multiple
)
67 while(data
.size() % multiple
)
71 void assembler::pad(size_t amount
)
73 for(size_t i
= 0; i
< amount
; i
++)
77 size_t assembler::size()
82 std::map
<std::string
, void*> assembler::flush(void* base
)
84 memcpy(base
, &data
[0], data
.size());
85 for(auto i
: relocs
) {
86 i
.promise((uint8_t*)base
+ i
.source
, i
.target
->resolve((addr_t
)base
), (addr_t
)base
+ i
.source
);
88 std::map
<std::string
, void*> ret
;
89 for(auto i
: globals
) {
90 ret
[i
.first
] = reinterpret_cast<void*>(i
.second
->resolve((addr_t
)base
));
95 void i386_reloc_rel8(uint8_t* location
, size_t target
, size_t source
)
97 int8_t d
= target
- source
- 1;
98 if(source
+ d
+ 1 != target
) {
99 std::cerr
<< "Out-of-range offset: " << d
<< std::endl
;
100 throw std::runtime_error("Relative reference (8-bit) out of range");
102 write8sle(location
, d
);
105 void i386_reloc_rel16(uint8_t* location
, size_t target
, size_t source
)
107 int16_t d
= target
- source
- 2;
108 if(source
+ d
+ 2 != target
) {
109 std::cerr
<< "Out-of-range offset: " << d
<< std::endl
;
110 throw std::runtime_error("Relative reference (16-bit) out of range");
112 write32sle(location
, d
);
115 void i386_reloc_rel32(uint8_t* location
, size_t target
, size_t source
)
117 int32_t d
= target
- source
- 4;
118 if(source
+ d
+ 4 != target
) {
119 std::cerr
<< "Out-of-range offset: " << d
<< std::endl
;
120 throw std::runtime_error("Relative reference (32-bit) out of range");
122 write32sle(location
, d
);
125 void i386_reloc_abs32(uint8_t* location
, size_t target
, size_t source
)
127 if(target
> 0xFFFFFFFFU
)
128 throw std::runtime_error("Absolute reference out of range");
129 write32ule(location
, target
);
132 void i386_reloc_abs64(uint8_t* location
, size_t target
, size_t source
)
134 write64ule(location
, target
);
137 uint8_t i386_modrm(uint8_t reg
, uint8_t mod
, uint8_t rm
)
139 return (mod
& 3) * 64 + (reg
& 7) * 8 + (rm
& 7);
142 uint8_t i386_sib(uint8_t base
, uint8_t index
, uint8_t scale
)
144 return (scale
& 3) * 64 + (index
& 7) * 8 + (base
& 7);
148 dynamic_code::dynamic_code(size_t size
)
150 #if !defined(_WIN32) && !defined(_WIN64)
151 asize
= (size
+ getpagesize() - 1) / getpagesize() * getpagesize();
152 base
= (uint8_t*)mmap(NULL
, asize
, PROT_READ
| PROT_WRITE
, MAP_PRIVATE
| MAP_ANONYMOUS
, -1, 0);
153 if(base
== MAP_FAILED
)
154 throw std::runtime_error("Failed to allocate memory for routine");
156 asize
= (size
+ 4095) >> 12 << 12; //Windows is always i386/amd64, right?
157 base
= VirtualAlloc(NULL
, asize
, MEM_COMMIT
| MEM_RESERVE
, PAGE_READWRITE
);
159 throw std::runtime_error("Failed to allocate memory for routine");
163 dynamic_code::~dynamic_code()
165 #if !defined(_WIN32) && !defined(_WIN64)
168 VirtualFree(base
, 0, MEM_RELEASE
);
172 void dynamic_code::commit()
174 #if !defined(_WIN32) && !defined(_WIN64)
175 if(mprotect(base
, asize
, PROT_READ
| PROT_EXEC
) < 0)
176 throw std::runtime_error("Failed to mark routine as executable");
179 if(!VirtualProtect(base
, asize
, PAGE_EXECUTE_READ
, &dummy
))
180 throw std::runtime_error("Failed to mark routine as executable");
184 uint8_t* dynamic_code::pointer() throw()
186 return reinterpret_cast<uint8_t*>(base
);