init
This commit is contained in:
commit
fb14fd90a4
13
.gitignore
vendored
Normal file
13
.gitignore
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
.obsidian
|
||||||
|
|
||||||
|
.direnv
|
||||||
|
|
||||||
|
\.idea/
|
||||||
|
|
||||||
|
cmake-build-debug/
|
||||||
|
|
||||||
|
cmake-build-release/
|
||||||
|
|
||||||
|
flush_flush/histogram/ff/calibration
|
||||||
|
|
||||||
|
flush_flush/histogram/ff/file
|
||||||
148
README.md
Normal file
148
README.md
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
## Flush+Reload Covert Channel
|
||||||
|
|
||||||
|
### Primitive
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
in `./src/lib.c` sind folgende Primitive `flush`, `reload` und `time_maccess`:
|
||||||
|
|
||||||
|
`maccess` greift auf diese Speicheradresse `addr` zu.
|
||||||
|
```C
|
||||||
|
void maccess(void* addr)
|
||||||
|
{
|
||||||
|
asm volatile ("movq (%0), %%rax\n"
|
||||||
|
:
|
||||||
|
: "c" (addr)
|
||||||
|
: "rax");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
`flush` verdrängt die Speicheradresse `addr` aus dem Cache.
|
||||||
|
```C
|
||||||
|
void flush(void* addr)
|
||||||
|
{
|
||||||
|
asm volatile ("clflush 0(%0)\n"
|
||||||
|
:
|
||||||
|
: "c" (addr)
|
||||||
|
: "rax");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`time_maccess` misst wie lange der Zugriff auf die Speicheradresse `addr` dauert.
|
||||||
|
|
||||||
|
Zum Messen der Dauer des Speicherzugriffs lesen wir vor und nach dem Zugriff die Zeit aus.
|
||||||
|
Um unsere Reihenfolge zu bewahren reicht das Ausschalten von Compiler Optimierungen ggfs. nicht aus. Um zu verhindern, dass die CPU die Instruktionen parallel oder in anderer Reihenfolge ausführt können sog. Fences verwendet werden:
|
||||||
|
|
||||||
|
```C
|
||||||
|
size_t time_maccess(void (* addr)(void))
|
||||||
|
{
|
||||||
|
uint64_t start, end, delta;
|
||||||
|
uint64_t lo, hi;
|
||||||
|
asm volatile ("LFENCE");
|
||||||
|
asm volatile ("RDTSC": "=a" (lo), "=d" (hi));
|
||||||
|
start = (hi<<32) | lo;
|
||||||
|
asm volatile ("LFENCE");
|
||||||
|
|
||||||
|
asm volatile ("movq (%0), %%rax\n"
|
||||||
|
:
|
||||||
|
: "c" (addr)
|
||||||
|
: "rax");
|
||||||
|
|
||||||
|
asm volatile ("LFENCE");
|
||||||
|
asm volatile ("RDTSC": "=a" (lo), "=d" (hi));
|
||||||
|
end = (hi<<32) | lo;
|
||||||
|
asm volatile ("LFENCE");
|
||||||
|
delta = end - start;
|
||||||
|
return delta;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### Block 1: Messen der Timing-Differenzen + Threshold bestimmen
|
||||||
|
|
||||||
|
##### Tips
|
||||||
|
- am besten kompiliert man ohne Compileroptimierungen (`-O0`):
|
||||||
|
```bash
|
||||||
|
gcc -O0 cache_test.c lib.c -o cache_test
|
||||||
|
```
|
||||||
|
- CMake ist praktisch! siehe `./src/CMakeList.txt`. Verwenden durch `cmake .` und dann `make`.
|
||||||
|
|
||||||
|
Muster: `./src/cache_test.c`
|
||||||
|
### Block 2: Signale über den Cache
|
||||||
|
|
||||||
|
**Jetzt können wir den Cache doch mal als Medium verwenden. Der Sender kann `0` und `1` über den (ausbleibenden) Speicherzugriff kodieren. Der Empfänger interpretiert dann, je nach Zugriffszeit.**
|
||||||
|
|
||||||
|
`sharedlib.c` sieht so aus:
|
||||||
|
|
||||||
|
```C
|
||||||
|
void function(void)
|
||||||
|
{ asm volatile (
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
"nop\n\t"
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Die Adresse von `function` kann also zum Flushen und Reloaded verwendet werden.
|
||||||
|
Da immer eine gesamte Cacheline geladen wird, sollte sich nichts anderes in dem selben 64Byte Block befinden.
|
||||||
|
Die Funktionen `padding_before` und `padding_after` sind beide 64 Byte groß, also eine Cacheline.
|
||||||
|
Damit kann dann auch gar nichts mehr schief gehen :)
|
||||||
|
|
||||||
|
`sharedlib.c` kann man so kompilieren und linken:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# sharedlib kompilieren
|
||||||
|
gcc -fPIC -shared -O0 -o libsharedlib.so sharedlib.c
|
||||||
|
# sharedlib bei Sender und Empfänger linken
|
||||||
|
gcc -O0 sender.c lib.c -L. -lsharedlib -o sender
|
||||||
|
gcc -O0 empfaenger.c lib.c -L. -lsharedlib -o empfaenger
|
||||||
|
# ggfs. muss man noch den PATH exportieren
|
||||||
|
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
|
||||||
|
```
|
||||||
|
|
||||||
|
*(oder einfach `cmake` verwenden)*
|
||||||
|
|
||||||
|
dann kann man `function` verwenden:
|
||||||
|
|
||||||
|
```C
|
||||||
|
# in e.g. sender.c
|
||||||
|
maccess((void *) function)
|
||||||
|
...
|
||||||
|
```
|
||||||
|
##### Tips
|
||||||
|
|
||||||
|
- `taskset` zum kann pinnen der Programme auf einen bestimmten CPU-Kern benutzt werden. Das kann helfen.
|
||||||
|
- Verwendet man blockierenden Sleep um zu Takten, z.B. `clock_nanosleep`, dann sollte man unbedingt darauf achten nicht eine Periodendauer zu schlafen, sondern nur bis zum nächsten Zeitabschnitt. Einfacher geht es mit nicht-blockierendem Sleep, z.B. `ualarm`.
|
||||||
|
|
||||||
|
So kann man `ualarm` nutzen, um alle x µs einen `SIGARLM` auszulösen:
|
||||||
|
|
||||||
|
```C
|
||||||
|
int main(void){
|
||||||
|
...
|
||||||
|
signal(SIGALRM, signal_handler);
|
||||||
|
ualarm(sample_interval, sample_interval);
|
||||||
|
```
|
||||||
|
|
||||||
|
Bei jedem `SIGALRM` Signal wird `signal_handler` ausgeführt:
|
||||||
|
|
||||||
|
```c
|
||||||
|
void signal_handler(int signo) {
|
||||||
|
if (signo == SIGALRM) {
|
||||||
|
# CODE HERE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- Der Zeitabstand von Flush zu Reload sollte MAXIMIERT werden! Dies ist das Zeitfenster, in welchem der Sender die Adresse(n) zurück in den Cache laden kann.
|
||||||
|
- Der Sender kann nicht nur einmal Laden. Das kann man auch mehrfach in einem Zeitfenster machen, um sicher zu gehen, dass die Cacheline auch geladen ist, wenn der Empfänger ausließt.
|
||||||
|
|
||||||
|
### Block 3: Einen String über den Cache als Medium senden
|
||||||
|
|
||||||
|
- Kann man irgendwie mehr als ein Bit gleichzeitig senden? ;)
|
||||||
|
|
||||||
|
Muster: `./src/sender.c` und `./src/receiver.c`
|
||||||
27
flake.lock
generated
Normal file
27
flake.lock
generated
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1739580444,
|
||||||
|
"narHash": "sha256-+/bSz4EAVbqz8/HsIGLroF8aNaO8bLRL7WfACN+24g4=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "8bb37161a0488b89830168b81c48aed11569cb93",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
25
flake.nix
Normal file
25
flake.nix
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
description = "Development environment with CMake, GCC, Clang, Python, Matplotlib, and Scikit-learn";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs }:
|
||||||
|
let
|
||||||
|
system = "x86_64-linux";
|
||||||
|
pkgs = import nixpkgs { inherit system; };
|
||||||
|
in {
|
||||||
|
devShells.${system}.default = pkgs.mkShell {
|
||||||
|
buildInputs = [
|
||||||
|
pkgs.cmake
|
||||||
|
pkgs.gcc
|
||||||
|
pkgs.clang
|
||||||
|
pkgs.python3
|
||||||
|
pkgs.python3Packages.matplotlib
|
||||||
|
pkgs.python3Packages.scikit-learn
|
||||||
|
pkgs.python3Packages.numpy
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
22
src/CMakeLists.txt
Normal file
22
src/CMakeLists.txt
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
project(cache_attacks C)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 99)
|
||||||
|
set(CMAKE_C_FLAGS "-O0" CACHE STRING "C Compiler flags" FORCE)
|
||||||
|
set(CMAKE_CXX_FLAGS "-O0" CACHE STRING "C++ Compiler flags" FORCE)
|
||||||
|
|
||||||
|
# Add shared library
|
||||||
|
add_library(sharedlib SHARED sharedlib.c sharedlib.h)
|
||||||
|
|
||||||
|
# Add the sender executable
|
||||||
|
add_executable(send send.c lib.c lib.h)
|
||||||
|
target_link_libraries(send sharedlib)
|
||||||
|
|
||||||
|
# Add the receiver executable
|
||||||
|
add_executable(recv recv.c lib.c lib.h)
|
||||||
|
target_link_libraries(recv sharedlib)
|
||||||
|
|
||||||
|
# add the cache-test executable
|
||||||
|
add_executable(cache_test cache_test.c lib.c lib.h)
|
||||||
|
target_link_libraries(cache_test sharedlib)
|
||||||
56
src/cache_test.c
Normal file
56
src/cache_test.c
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "lib.h"
|
||||||
|
#include "sharedlib.h"
|
||||||
|
|
||||||
|
#define NUM_ACCESSES 1000000
|
||||||
|
|
||||||
|
void measure_multiple_accesses(void (*addr)(void), size_t num_accesses, size_t* hits, size_t* misses)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < num_accesses; i++)
|
||||||
|
{
|
||||||
|
flush((void*) addr);
|
||||||
|
misses[i] = time_maccess(addr);
|
||||||
|
|
||||||
|
maccess((void*) addr);
|
||||||
|
hits[i] = time_maccess(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t find_crossover_point(size_t* hits, size_t* misses, size_t num_accesses)
|
||||||
|
{
|
||||||
|
size_t hit_sum = 0, miss_sum = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_accesses; i++)
|
||||||
|
{
|
||||||
|
hit_sum += hits[i];
|
||||||
|
miss_sum += misses[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t avg_hit = hit_sum / num_accesses;
|
||||||
|
size_t avg_miss = miss_sum / num_accesses;
|
||||||
|
|
||||||
|
return (avg_hit + avg_miss) / 2; // Midpoint as threshold
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
size_t* hits = malloc(NUM_ACCESSES * sizeof(size_t));
|
||||||
|
size_t* misses = malloc(NUM_ACCESSES * sizeof(size_t));
|
||||||
|
|
||||||
|
if (!hits || !misses)
|
||||||
|
{
|
||||||
|
perror("Memory allocation failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
measure_multiple_accesses((void*) function, NUM_ACCESSES, hits, misses);
|
||||||
|
|
||||||
|
size_t threshold = find_crossover_point(hits, misses, NUM_ACCESSES);
|
||||||
|
printf("Suggested threshold: %zu\n", threshold);
|
||||||
|
|
||||||
|
free(hits);
|
||||||
|
free(misses);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
59
src/lib.c
Normal file
59
src/lib.c
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#include "lib.h"
|
||||||
|
|
||||||
|
size_t time_flush(void (* addr)(void))
|
||||||
|
{
|
||||||
|
uint64_t start, end, delta;
|
||||||
|
uint64_t lo, hi;
|
||||||
|
asm volatile ("LFENCE");
|
||||||
|
asm volatile ("RDTSC": "=a" (lo), "=d" (hi));
|
||||||
|
start = (hi<<32) | lo;
|
||||||
|
asm volatile ("LFENCE");
|
||||||
|
|
||||||
|
asm volatile ("CLFLUSH 0(%0)\n":: "c" (addr): "rax");
|
||||||
|
|
||||||
|
asm volatile ("MFENCE");
|
||||||
|
asm volatile ("RDTSC": "=a" (lo), "=d" (hi));
|
||||||
|
end = (hi<<32) | lo;
|
||||||
|
asm volatile ("LFENCE");
|
||||||
|
delta = end - start;
|
||||||
|
return delta;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t time_maccess(void (* addr)(void))
|
||||||
|
{
|
||||||
|
uint64_t start, end, delta;
|
||||||
|
uint64_t lo, hi;
|
||||||
|
asm volatile ("LFENCE");
|
||||||
|
asm volatile ("RDTSC": "=a" (lo), "=d" (hi));
|
||||||
|
start = (hi<<32) | lo;
|
||||||
|
asm volatile ("LFENCE");
|
||||||
|
|
||||||
|
asm volatile ("movq (%0), %%rax\n"
|
||||||
|
:
|
||||||
|
: "c" (addr)
|
||||||
|
: "rax");
|
||||||
|
|
||||||
|
asm volatile ("LFENCE");
|
||||||
|
asm volatile ("RDTSC": "=a" (lo), "=d" (hi));
|
||||||
|
end = (hi<<32) | lo;
|
||||||
|
asm volatile ("LFENCE");
|
||||||
|
delta = end - start;
|
||||||
|
return delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
void maccess(void* p)
|
||||||
|
{
|
||||||
|
asm volatile ("movq (%0), %%rax\n"
|
||||||
|
:
|
||||||
|
: "c" (p)
|
||||||
|
: "rax");
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush(void* p)
|
||||||
|
{
|
||||||
|
asm volatile ("clflush 0(%0)\n"
|
||||||
|
:
|
||||||
|
: "c" (p)
|
||||||
|
: "rax");
|
||||||
|
}
|
||||||
9
src/lib.h
Normal file
9
src/lib.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# pragma once
|
||||||
|
|
||||||
|
#include <stddef.h> // For size_t
|
||||||
|
#include <stdint.h> // For uint64_t
|
||||||
|
|
||||||
|
void maccess(void* p);
|
||||||
|
void flush(void* p);
|
||||||
|
size_t time_maccess(void (*addr)(void));
|
||||||
|
size_t time_flush(void (*addr)(void));
|
||||||
27
src/mksharedlib.py
Normal file
27
src/mksharedlib.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
def generate_nop_function(filename="sharedlib.c"):
|
||||||
|
with open(filename, "w") as f:
|
||||||
|
f.write("#include \"sharedlib.h\"\n\n")
|
||||||
|
|
||||||
|
f.write("void padding_before(void) { asm volatile (\n")
|
||||||
|
for _ in range(64):
|
||||||
|
f.write(" \"nop\\n\\t\"\n")
|
||||||
|
f.write(" :::\n); }\n\n")
|
||||||
|
|
||||||
|
f.write("void function(void)\n{")
|
||||||
|
f.write(" asm volatile (\n")
|
||||||
|
|
||||||
|
size = 64 * 256
|
||||||
|
for _ in range(size):
|
||||||
|
f.write(" \"nop\\n\\t\"\n")
|
||||||
|
|
||||||
|
f.write(" :::\n );\n}")
|
||||||
|
|
||||||
|
f.write("\n\nvoid padding_after(void) { asm volatile (\n")
|
||||||
|
for _ in range(64):
|
||||||
|
f.write(" \"nop\\n\\t\"\n")
|
||||||
|
f.write(" :::\n); }\n")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
generate_nop_function()
|
||||||
98
src/recv.c
Normal file
98
src/recv.c
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "lib.h"
|
||||||
|
#include "sharedlib.h"
|
||||||
|
|
||||||
|
#define BITS 8
|
||||||
|
#define BUFFER_SIZE 256
|
||||||
|
|
||||||
|
volatile uint8_t buffer[BUFFER_SIZE];
|
||||||
|
volatile size_t byte_index = 0;
|
||||||
|
volatile int sample_interval = 100; // Default: 100 µs
|
||||||
|
volatile int threshold = 245; // Default: 245 cycles
|
||||||
|
|
||||||
|
void signal_handler(int signo) {
|
||||||
|
if (signo == SIGALRM)
|
||||||
|
{
|
||||||
|
// Check if buffer is full
|
||||||
|
if (byte_index >= BUFFER_SIZE)
|
||||||
|
{
|
||||||
|
ualarm(0, 0); // Stop sampling
|
||||||
|
printf("Buffer full. Stopping capture.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive a byte
|
||||||
|
uint8_t byte = 0;
|
||||||
|
for (int i = 0; i < BITS; i++)
|
||||||
|
{
|
||||||
|
size_t time = time_maccess((void *) function + (i << 9));
|
||||||
|
if (time < threshold)
|
||||||
|
{
|
||||||
|
// set the ith bit of byte to 1 if it was a cache hit
|
||||||
|
byte |= (1 << i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// flush the cache
|
||||||
|
for (int i = 0; i < BITS; i++)
|
||||||
|
{
|
||||||
|
flush((void *) function + (i << 9));
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[byte_index++] = byte; // Store received byte
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
if (argc < 3)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: %s <sample_interval> <threshold>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sample_interval = atoi(argv[1]);
|
||||||
|
threshold = atoi(argv[2]);
|
||||||
|
|
||||||
|
printf("Receiver started with sample interval: %d µs, threshold: %d cycles\n", sample_interval, threshold);
|
||||||
|
|
||||||
|
// Flush the cache once before starting
|
||||||
|
for (int i = 0; i < BITS; i++)
|
||||||
|
{
|
||||||
|
flush((void *) function + (i << 9));
|
||||||
|
}
|
||||||
|
|
||||||
|
signal(SIGALRM, signal_handler);
|
||||||
|
ualarm(sample_interval, sample_interval);
|
||||||
|
|
||||||
|
while (byte_index < BUFFER_SIZE) {
|
||||||
|
pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print received bytes in hex
|
||||||
|
printf("Received %zu bytes:\n", byte_index);
|
||||||
|
for (size_t i = 0; i < byte_index; i++) {
|
||||||
|
printf("%02X ", buffer[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// Print as ASCII characters
|
||||||
|
printf("ASCII Output:\n");
|
||||||
|
for (size_t i = 0; i < byte_index; i++) {
|
||||||
|
//if (buffer[i] >= 32 && buffer[i] <= 126) // Printable ASCII
|
||||||
|
if (isalnum(buffer[i]))
|
||||||
|
{
|
||||||
|
printf("%c", buffer[i]);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
printf("."); // Placeholder for non-printables
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
64
src/send.c
Normal file
64
src/send.c
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "lib.h"
|
||||||
|
#include "sharedlib.h"
|
||||||
|
|
||||||
|
#define BITS 8
|
||||||
|
|
||||||
|
volatile uint8_t *buffer = NULL;
|
||||||
|
volatile size_t buffer_len = 0;
|
||||||
|
volatile size_t current_index = 0;
|
||||||
|
volatile uint8_t byte_to_send = 0;
|
||||||
|
|
||||||
|
void signal_handler(int signo)
|
||||||
|
{
|
||||||
|
if (signo == SIGALRM)
|
||||||
|
{
|
||||||
|
if (current_index < buffer_len)
|
||||||
|
{
|
||||||
|
byte_to_send = buffer[current_index++];
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
current_index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (argc < 3)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: %s <string> <sample_interval>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = (uint8_t *) argv[1];
|
||||||
|
buffer_len = strlen(argv[1]);
|
||||||
|
int sample_interval = atoi(argv[2]);
|
||||||
|
|
||||||
|
// set up an alarm signal that triggers every timeframe
|
||||||
|
signal(SIGALRM, signal_handler);
|
||||||
|
ualarm(sample_interval, sample_interval);
|
||||||
|
|
||||||
|
// during the timeframe, continuously send the signal
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < BITS; i++)
|
||||||
|
{
|
||||||
|
if (byte_to_send & (1 << i))
|
||||||
|
{
|
||||||
|
maccess((void *) function + (i<<9));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
flush((void *) function + (i<<9));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
16527
src/sharedlib.c
Normal file
16527
src/sharedlib.c
Normal file
File diff suppressed because it is too large
Load Diff
9
src/sharedlib.h
Normal file
9
src/sharedlib.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef SHAREDLIB_H
|
||||||
|
#define SHAREDLIB_H
|
||||||
|
|
||||||
|
// Function declarations
|
||||||
|
void padding_before(void);
|
||||||
|
void function(void);
|
||||||
|
void padding_after(void);
|
||||||
|
|
||||||
|
#endif // SHAREDLIB_H
|
||||||
Loading…
Reference in New Issue
Block a user