1 #include "assembler.hpp"
2 #include "serialization.hpp"
8 #if !defined(_WIN32) && !defined(_WIN64)
18 #define MAP_ANONYMOUS MAP_ANON
24 label_list::operator label
&()
26 labels
.push_back(label());
30 label_list::operator label
*()
32 labels
.push_back(label());
33 return &labels
.back();
36 label
& label_list::external(void* addr
)
38 labels
.push_back(label());
39 labels
.back() = label(addr
);
43 assembler::assembler()
47 void assembler::_label(label
& l
)
52 void assembler::_label(label
& l
, const std::string
& globalname
)
55 globals
[globalname
] = &l
;
58 void assembler::byte(uint8_t b
)
63 void assembler::byte(std::initializer_list
<uint8_t> b
)
69 void assembler::byte(const uint8_t* b
, size_t l
)
71 for(size_t i
= 0; i
< l
; i
++)
75 void assembler::relocation(std::function
<void(uint8_t* location
, size_t target
, size_t source
)> promise
,
81 r
.source
= data
.size();
85 void assembler::align(size_t multiple
)
89 while(data
.size() % multiple
)
93 void assembler::pad(size_t amount
)
95 for(size_t i
= 0; i
< amount
; i
++)
99 size_t assembler::size()
104 std::map
<std::string
, void*> assembler::flush(void* base
)
106 memcpy(base
, &data
[0], data
.size());
107 for(auto i
: relocs
) {
108 i
.promise((uint8_t*)base
+ i
.source
, i
.target
->resolve((addr_t
)base
), (addr_t
)base
+ i
.source
);
110 std::map
<std::string
, void*> ret
;
111 for(auto i
: globals
) {
112 ret
[i
.first
] = reinterpret_cast<void*>(i
.second
->resolve((addr_t
)base
));
117 void assembler::dump(const std::string
& basename
, const std::string
& name
, void* base
,
118 std::map
<std::string
, void*> map
)
120 static unsigned x
= 0;
121 std::string realbase
= (stringfmt() << basename
<< "." << (x
++)).str();
123 std::ofstream
symbols1(realbase
+ ".syms");
124 symbols1
<< hex::to
<size_t>((size_t)base
, false) << " __base(" << name
<< ")" << std::endl
;
126 symbols1
<< hex::to
<size_t>((size_t)i
.second
, false) << " " << i
.first
<< std::endl
;
127 symbols1
<< hex::to
<size_t>((size_t)base
+ data
.size(), false) << " __end" << std::endl
;
130 //Dump generated binary.
131 std::ofstream
symbols2(realbase
+ ".bin", std::ios::binary
);
132 for(unsigned i
= 0; i
< data
.size(); i
++)
133 symbols2
<< ((char*)base
)[i
];
137 void i386_reloc_rel8(uint8_t* location
, size_t target
, size_t source
)
139 int8_t d
= target
- source
- 1;
140 if(source
+ d
+ 1 != target
) {
141 std::cerr
<< "Out-of-range offset: " << d
<< std::endl
;
142 throw std::runtime_error("Relative reference (8-bit) out of range");
144 serialization::s8l(location
, d
);
147 void i386_reloc_rel16(uint8_t* location
, size_t target
, size_t source
)
149 int16_t d
= target
- source
- 2;
150 if(source
+ d
+ 2 != target
) {
151 std::cerr
<< "Out-of-range offset: " << d
<< std::endl
;
152 throw std::runtime_error("Relative reference (16-bit) out of range");
154 serialization::s32l(location
, d
);
157 void i386_reloc_rel32(uint8_t* location
, size_t target
, size_t source
)
159 int32_t d
= target
- source
- 4;
160 if(source
+ d
+ 4 != target
) {
161 std::cerr
<< "Out-of-range offset: " << d
<< std::endl
;
162 throw std::runtime_error("Relative reference (32-bit) out of range");
164 serialization::s32l(location
, d
);
167 void i386_reloc_abs32(uint8_t* location
, size_t target
, size_t source
)
169 if(target
> 0xFFFFFFFFU
)
170 throw std::runtime_error("Absolute reference out of range");
171 serialization::u32l(location
, target
);
174 void i386_reloc_abs64(uint8_t* location
, size_t target
, size_t source
)
176 serialization::u64l(location
, target
);
179 uint8_t i386_modrm(uint8_t reg
, uint8_t mod
, uint8_t rm
)
181 return (mod
& 3) * 64 + (reg
& 7) * 8 + (rm
& 7);
184 uint8_t i386_sib(uint8_t base
, uint8_t index
, uint8_t scale
)
186 return (scale
& 3) * 64 + (index
& 7) * 8 + (base
& 7);
190 dynamic_code::dynamic_code(size_t size
)
192 #if !defined(_WIN32) && !defined(_WIN64)
193 asize
= (size
+ getpagesize() - 1) / getpagesize() * getpagesize();
194 base
= (uint8_t*)mmap(NULL
, asize
, PROT_READ
| PROT_WRITE
, MAP_PRIVATE
| MAP_ANONYMOUS
, -1, 0);
195 if(base
== MAP_FAILED
)
196 throw std::runtime_error("Failed to allocate memory for routine");
198 asize
= (size
+ 4095) >> 12 << 12; //Windows is always i386/amd64, right?
199 base
= VirtualAlloc(NULL
, asize
, MEM_COMMIT
| MEM_RESERVE
, PAGE_READWRITE
);
201 throw std::runtime_error("Failed to allocate memory for routine");
205 dynamic_code::~dynamic_code()
207 #if !defined(_WIN32) && !defined(_WIN64)
210 VirtualFree(base
, 0, MEM_RELEASE
);
214 void dynamic_code::commit()
216 #if !defined(_WIN32) && !defined(_WIN64)
217 if(mprotect(base
, asize
, PROT_READ
| PROT_EXEC
) < 0)
218 throw std::runtime_error("Failed to mark routine as executable");
221 if(!VirtualProtect(base
, asize
, PAGE_EXECUTE_READ
, &dummy
))
222 throw std::runtime_error("Failed to mark routine as executable");
226 uint8_t* dynamic_code::pointer() throw()
228 return reinterpret_cast<uint8_t*>(base
);