Можно использовать эти Stopwatch
, предполагая использование.NET 2.0 или более новые.
System.Diagnostics.Stopwatch.StartNew();
Stopwatch
класс также имеет общедоступное поле IsHighResolution
только для чтения, которое сообщит, основан ли секундомер на счетчике производительности с высоким разрешением. Если не, это основано на системном таймере.
я не уверен, что это берет для секундомера, чтобы быть основанным на счетчике производительности с высоким разрешением. Существуют некоторые вызовы API, но я фигурирую, не использует ли секундомер высокое разрешение, то API, вероятно, не там.
, Что необходимо запустить тест: Linux x86 или x64 (в моем случае, я использую Ubuntu x64)
Позволяют нам Запуститься
, Этот блок (x86) перемещает значение 666 в регистр eax:
movl $666, %eax
ret
Позволяют нам сделать двоичное представление из него:
код операции movl (movl mov с размером операнда 32) в двоичном файле = 1011
Инструкция , ширина в двоичном файле = 1
Регистр , eax в двоичном файле = 000
, Номер 666 в двоичном файле на 32 бита со знаком = 00000000 00000000 00000010 10011010
666 преобразован в [1 147], прямой порядок байтов = 10011010 00000010 00000000 00000000
, Инструкция мочит (возврат) в двоичном файле, = 11000011
Поэтому наконец, наши чистые двоичные инструкции будут похожи на это:
1011(movl)1(width)000(eax)10011010000000100000000000000000(666)
11000011(ret)
Соединение всего этого:
1011100010011010000000100000000000000000
11000011
Для выполнения его двоичный код должен быть помещен в страницу памяти с полномочиями выполнения, мы можем сделать то использование следующего кода C:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
/* Allocate size bytes of executable memory. */
unsigned char *alloc_exec_mem(size_t size)
{
void *ptr;
ptr = mmap(0, size, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANON, -1, 0);
if (ptr == MAP_FAILED) {
perror("mmap");
exit(1);
}
return ptr;
}
/* Read up to buffer_size bytes, encoded as 1's and 0's, into buffer. */
void read_ones_and_zeros(unsigned char *buffer, size_t buffer_size)
{
unsigned char byte = 0;
int bit_index = 0;
int c;
while ((c = getchar()) != EOF) {
if (isspace(c)) {
continue;
} else if (c != '0' && c != '1') {
fprintf(stderr, "error: expected 1 or 0!\n");
exit(1);
}
byte = (byte << 1) | (c == '1');
bit_index++;
if (bit_index == 8) {
if (buffer_size == 0) {
fprintf(stderr, "error: buffer full!\n");
exit(1);
}
*buffer++ = byte;
--buffer_size;
byte = 0;
bit_index = 0;
}
}
if (bit_index != 0) {
fprintf(stderr, "error: left-over bits!\n");
exit(1);
}
}
int main()
{
typedef int (*func_ptr_t)(void);
func_ptr_t func;
unsigned char *mem;
int x;
mem = alloc_exec_mem(1024);
func = (func_ptr_t) mem;
read_ones_and_zeros(mem, 1024);
x = (*func)();
printf("function returned %d\n", x);
return 0;
}
Источник: https://www.hanshq.net/files/ones-and-zeros_42.c
Мы можем скомпилировать его использование:
gcc source.c -o binaryexec
Для выполнения его:
./binaryexec
Затем мы передаем первые наборы инструкций:
1011100010011010000000100000000000000000
нажимают Enter
и передают инструкцию по возврату:
11000011
нажимают Enter
наконец ctrl+d, чтобы закончить программу и получить вывод:
функция возвратилась 666