1 #include "assembler.hpp"
2 #include "serialization.hpp"
9 #if !defined(_WIN32) && !defined(_WIN64)
19 #define MAP_ANONYMOUS MAP_ANON
25 label_list::operator label
&()
27 labels
.push_back(label());
31 label_list::operator label
*()
33 labels
.push_back(label());
34 return &labels
.back();
37 label
& label_list::external(void* addr
)
39 labels
.push_back(label());
40 labels
.back() = label(addr
);
44 assembler::assembler()
48 void assembler::_label(label
& l
)
53 void assembler::_label(label
& l
, const std::string
& globalname
)
56 globals
[globalname
] = &l
;
59 void assembler::byte(uint8_t b
)
64 void assembler::byte(std::initializer_list
<uint8_t> b
)
70 void assembler::byte(const uint8_t* b
, size_t l
)
72 for(size_t i
= 0; i
< l
; i
++)
76 void assembler::relocation(std::function
<void(uint8_t* location
, size_t target
, size_t source
)> promise
,
82 r
.source
= data
.size();
86 void assembler::align(size_t multiple
)
90 while(data
.size() % multiple
)
94 void assembler::pad(size_t amount
)
96 for(size_t i
= 0; i
< amount
; i
++)
100 size_t assembler::size()
105 std::map
<std::string
, void*> assembler::flush(void* base
)
107 memcpy(base
, &data
[0], data
.size());
108 for(auto i
: relocs
) {
109 i
.promise((uint8_t*)base
+ i
.source
, i
.target
->resolve((addr_t
)base
), (addr_t
)base
+ i
.source
);
111 std::map
<std::string
, void*> ret
;
112 for(auto i
: globals
) {
113 ret
[i
.first
] = reinterpret_cast<void*>(i
.second
->resolve((addr_t
)base
));
118 void assembler::dump(const std::string
& basename
, const std::string
& name
, void* base
,
119 std::map
<std::string
, void*> map
)
121 static unsigned x
= 0;
122 std::string realbase
= (stringfmt() << basename
<< "." << (x
++)).str();
124 std::ofstream
symbols1(realbase
+ ".syms");
125 symbols1
<< hex::to
<size_t>((size_t)base
, false) << " __base(" << name
<< ")" << std::endl
;
127 symbols1
<< hex::to
<size_t>((size_t)i
.second
, false) << " " << i
.first
<< std::endl
;
128 symbols1
<< hex::to
<size_t>((size_t)base
+ data
.size(), false) << " __end" << std::endl
;
131 //Dump generated binary.
132 std::ofstream
symbols2(realbase
+ ".bin", std::ios::binary
);
133 for(unsigned i
= 0; i
< data
.size(); i
++)
134 symbols2
<< ((char*)base
)[i
];
138 void i386_reloc_rel8(uint8_t* location
, size_t target
, size_t source
)
140 int8_t d
= target
- source
- 1;
141 if(source
+ d
+ 1 != target
) {
142 std::cerr
<< "Out-of-range offset: " << d
<< std::endl
;
143 throw std::runtime_error("Relative reference (8-bit) out of range");
145 serialization::s8l(location
, d
);
148 void i386_reloc_rel16(uint8_t* location
, size_t target
, size_t source
)
150 int16_t d
= target
- source
- 2;
151 if(source
+ d
+ 2 != target
) {
152 std::cerr
<< "Out-of-range offset: " << d
<< std::endl
;
153 throw std::runtime_error("Relative reference (16-bit) out of range");
155 serialization::s32l(location
, d
);
158 void i386_reloc_rel32(uint8_t* location
, size_t target
, size_t source
)
160 int32_t d
= target
- source
- 4;
161 if(source
+ d
+ 4 != target
) {
162 std::cerr
<< "Out-of-range offset: " << d
<< std::endl
;
163 throw std::runtime_error("Relative reference (32-bit) out of range");
165 serialization::s32l(location
, d
);
168 void i386_reloc_abs32(uint8_t* location
, size_t target
, size_t source
)
170 if(target
> 0xFFFFFFFFU
)
171 throw std::runtime_error("Absolute reference out of range");
172 serialization::u32l(location
, target
);
175 void i386_reloc_abs64(uint8_t* location
, size_t target
, size_t source
)
177 serialization::u64l(location
, target
);
180 uint8_t i386_modrm(uint8_t reg
, uint8_t mod
, uint8_t rm
)
182 return (mod
& 3) * 64 + (reg
& 7) * 8 + (rm
& 7);
185 uint8_t i386_sib(uint8_t base
, uint8_t index
, uint8_t scale
)
187 return (scale
& 3) * 64 + (index
& 7) * 8 + (base
& 7);
191 dynamic_code::dynamic_code(size_t size
)
193 #if !defined(_WIN32) && !defined(_WIN64)
194 asize
= (size
+ getpagesize() - 1) / getpagesize() * getpagesize();
195 base
= (uint8_t*)mmap(NULL
, asize
, PROT_READ
| PROT_WRITE
, MAP_PRIVATE
| MAP_ANONYMOUS
, -1, 0);
196 if(base
== MAP_FAILED
)
197 throw std::runtime_error("Failed to allocate memory for routine");
199 asize
= (size
+ 4095) >> 12 << 12; //Windows is always i386/amd64, right?
200 base
= VirtualAlloc(NULL
, asize
, MEM_COMMIT
| MEM_RESERVE
, PAGE_READWRITE
);
202 throw std::runtime_error("Failed to allocate memory for routine");
206 dynamic_code::~dynamic_code()
208 #if !defined(_WIN32) && !defined(_WIN64)
211 VirtualFree(base
, 0, MEM_RELEASE
);
215 void dynamic_code::commit()
217 #if !defined(_WIN32) && !defined(_WIN64)
218 if(mprotect(base
, asize
, PROT_READ
| PROT_EXEC
) < 0)
219 throw std::runtime_error("Failed to mark routine as executable");
222 if(!VirtualProtect(base
, asize
, PAGE_EXECUTE_READ
, &dummy
))
223 throw std::runtime_error("Failed to mark routine as executable");
227 uint8_t* dynamic_code::pointer() throw()
229 return reinterpret_cast<uint8_t*>(base
);