2011-07-08 23:25:58 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
header('Content-type: application/json');
|
|
|
|
|
|
|
|
/* Configuration */
|
|
|
|
$maxLength = 2048;
|
2011-07-09 22:19:17 +02:00
|
|
|
$allowedMmcus = array('attiny15', 'attiny45', 'atmega8u2', 'atmega8', 'atmega328p', 'atmega644p', 'atxmega128a1', 'attiny28', 'attiny48', 'atmega603', 'atmega103', 'attiny167', 'atmega48', 'atmega16', 'atmega1284p', 'atmega2560');
|
2011-07-08 23:25:58 +02:00
|
|
|
|
|
|
|
$oLevel = (isset($_GET['olevel'])) ? (int) $_GET['olevel'] : 0;
|
|
|
|
$mmcu = (isset($_GET['mmcu'])) ? $_GET['mmcu'] : 'atmega8';
|
|
|
|
$format = (isset($_GET['format'])) ? $_GET['format'] : 'bin';
|
2011-07-12 20:06:38 +02:00
|
|
|
$comments = isset($_GET['comments']) && $_GET['comments'] == '1';
|
2011-07-08 23:25:58 +02:00
|
|
|
|
|
|
|
$codeFile = tempnam('/tmp', 'tc_in_') . '.c';
|
|
|
|
$code = file_get_contents('php://input');
|
|
|
|
file_put_contents($codeFile, $code);
|
|
|
|
|
|
|
|
if (!in_array($mmcu, $allowedMmcus)) {
|
|
|
|
$messages = array('Are you kidding me?!');
|
|
|
|
}
|
|
|
|
elseif (strlen($code) > $maxLength) {
|
|
|
|
$messages = array('Die Maximale Codelänge wurde überschritten (' . $maxLength . ')');
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// compile
|
|
|
|
$outFile = tempnam('/tmp', 'tc_out_');
|
2011-07-13 00:19:05 +02:00
|
|
|
$disableOptimize = ' -O0 -fno-align-loops -fno-argument-alias' .
|
|
|
|
' -fno-auto-inc-dec -fno-branch-count-reg -fno-common' .
|
|
|
|
' -fno-early-inlining -fno-eliminate-unused-debug-types' .
|
|
|
|
' -fno-function-cse -fno-gcse-lm -fno-ident -fno-ivopts' .
|
|
|
|
' -fno-keep-static-consts -fno-leading-underscore' .
|
|
|
|
' -fmath-errno -fno-merge-debug-strings' .
|
|
|
|
' -fno-move-loop-invariants -fpeephole -fno-reg-struct-return' .
|
|
|
|
' -fno-sched-interblock -fno-sched-spec -fno-sched-stalled-insns-dep' .
|
|
|
|
' -fno-signed-zeros -fno-split-ivs-in-unroller' .
|
|
|
|
' -fno-toplevel-reorder -fno-trapping-math -fno-tree-cselim' .
|
|
|
|
' -fno-tree-loop-im -fno-tree-loop-ivcanon -fno-tree-loop-optimize' .
|
|
|
|
' -fno-tree-reassoc -fno-tree-scev-cprop -fno-tree-vect-loop-version' .
|
|
|
|
' -fno-var-tracking -fno-verbose-asm -fno-zero-initialized-in-bss' .
|
|
|
|
' -fno-argument-noalias -fno-math-errno' .
|
|
|
|
' -fno-pcc-struct-return -fno-peephole';
|
|
|
|
|
2011-07-12 20:06:38 +02:00
|
|
|
$cmd = 'avr-gcc -mmcu=' . $mmcu . ' -g3 -o ' . $outFile . ' ' . $codeFile;
|
|
|
|
|
|
|
|
if ($oLevel < 0) {
|
|
|
|
$cmd .= $disableOptimize;
|
|
|
|
}
|
|
|
|
else if ($oLevel >= 0) {
|
|
|
|
$cmd .= ' -O' . $oLevel;
|
|
|
|
}
|
|
|
|
|
|
|
|
exec($cmd . ' 2>&1', $messages, $result);
|
2011-07-08 23:25:58 +02:00
|
|
|
|
|
|
|
// objdump
|
2011-07-09 22:19:17 +02:00
|
|
|
$cmd = 'avr-objdump -w -d -l -z ' . $outFile . ' 2>&1';
|
2011-07-08 23:25:58 +02:00
|
|
|
$dump = shell_exec($cmd);
|
|
|
|
|
|
|
|
// refactor
|
|
|
|
$dumpLines = explode("\n", $dump);
|
2011-07-09 22:19:17 +02:00
|
|
|
$lastMapping = null;
|
|
|
|
$lastLine = null;
|
2011-07-12 20:06:38 +02:00
|
|
|
$assembler = array();
|
|
|
|
$byte = array();
|
|
|
|
$mnemonics = array();
|
2011-07-10 18:23:34 +02:00
|
|
|
$mapping = array(
|
|
|
|
'ansic' => array(), // ansic => assembler
|
2011-07-12 20:06:38 +02:00
|
|
|
'assembler' => array(), // assembler => bytecode (1:1)
|
|
|
|
'byte' => array() // bytecode => assembler (1:1)
|
2011-07-10 18:23:34 +02:00
|
|
|
);
|
2011-07-08 23:25:58 +02:00
|
|
|
|
|
|
|
foreach ($dumpLines as $line) { // parsing objdump
|
2011-07-12 20:06:38 +02:00
|
|
|
if (preg_match( // mnemonic
|
|
|
|
'/^\s{2}([0-9a-f]{2}):\t' . // address \s{2}9a:\ŧ
|
|
|
|
'((?:[0-9a-f]{2}\s)+)\s+' . // byte ec e5\s+\t
|
|
|
|
'([a-z]{2,6})\t' . // mnemonic ldi\t
|
|
|
|
'([^;\t]+)' . // operands r30, 0x5C\t\s;
|
|
|
|
'(?:\t;\s(.*))?/', // comment \s92
|
|
|
|
$line, $matches)) {
|
|
|
|
$as = $matches[3] . "\t" . $matches[4];
|
|
|
|
if ($comments && isset($matches[5])) {
|
|
|
|
$as .= "\t; " . $matches[5];
|
|
|
|
}
|
|
|
|
|
|
|
|
// reorder bytes
|
|
|
|
$bytes = array_map('hexdec', explode(' ', trim($matches[2])));
|
|
|
|
if (count($bytes) == 4) { // double word instruction
|
|
|
|
$bytes = array($bytes[1], $bytes[0], $bytes[3], $bytes[2]);
|
|
|
|
}
|
|
|
|
else { // single word instruction
|
|
|
|
$bytes = array($bytes[1], $bytes[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
$assembler[] = $as;
|
|
|
|
$byte[] = format($bytes, $format);
|
|
|
|
$mnemonics[$matches[3]] = (isset($mnemonics[$matches[3]])) ? $mnemonics[$matches[3]] + 1 : 1;
|
2011-07-13 00:19:05 +02:00
|
|
|
|
2011-07-10 18:23:34 +02:00
|
|
|
$mapping['assembler'][count($assembler)] = count($byte);
|
2011-07-12 20:06:38 +02:00
|
|
|
$mapping['byte'][count($byte)] = count($assembler);
|
2011-07-08 23:25:58 +02:00
|
|
|
}
|
2011-07-09 22:19:17 +02:00
|
|
|
elseif (preg_match('/^([0-9a-f]{8}) <(.*)>:/', $line, $matches)) { // label
|
2011-07-08 23:25:58 +02:00
|
|
|
$assembler[] = $matches[2] . ':';
|
|
|
|
}
|
2011-07-09 22:19:17 +02:00
|
|
|
elseif (preg_match('~^' . $codeFile . ':([0-9]+)~', $line, $matches)) { // mapping
|
|
|
|
$currentMapping = count($assembler);
|
|
|
|
$currentLine = $matches[1];
|
|
|
|
|
|
|
|
if ($lastMapping && $lastLine) {
|
2011-07-10 18:23:34 +02:00
|
|
|
$mapping['ansic'][$lastLine] = array($lastMapping, $currentMapping);
|
2011-07-09 22:19:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$lastLine = $currentLine;
|
|
|
|
$lastMapping = $currentMapping+1;
|
2011-07-08 23:25:58 +02:00
|
|
|
}
|
|
|
|
}
|
2011-07-09 22:19:17 +02:00
|
|
|
|
|
|
|
// Rest
|
2011-07-12 20:06:38 +02:00
|
|
|
$mapping['ansic'][$lastLine] = array($lastMapping, count($assembler));
|
2011-07-08 23:25:58 +02:00
|
|
|
}
|
|
|
|
|
2011-07-12 20:06:38 +02:00
|
|
|
arsort($mnemonics);
|
|
|
|
|
2011-07-08 23:25:58 +02:00
|
|
|
$json = array(
|
|
|
|
'result' => $result,
|
|
|
|
'messages' => implode("\n", $messages),
|
|
|
|
'code' => array(
|
|
|
|
'assembler' => implode("\n", $assembler),
|
|
|
|
'byte' => implode("\n", $byte)
|
|
|
|
),
|
2011-07-12 20:06:38 +02:00
|
|
|
'mapping' => $mapping,
|
|
|
|
'stats' => $mnemonics
|
2011-07-08 23:25:58 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
echo json_encode($json);
|
|
|
|
|
|
|
|
unlink($codeFile);
|
|
|
|
unlink($outFile);
|
|
|
|
|
|
|
|
function format($data, $format) {
|
|
|
|
if ($format == 'hex') {
|
2011-07-12 20:06:38 +02:00
|
|
|
return implode(' ', array_map(function($value) {
|
|
|
|
return str_pad(dechex($value), 2, '0', STR_PAD_LEFT);
|
|
|
|
}, $data));
|
2011-07-08 23:25:58 +02:00
|
|
|
}
|
|
|
|
else if ($format == 'dec') {
|
2011-07-12 20:06:38 +02:00
|
|
|
return implode(' ', array_map(function($value) {
|
|
|
|
return str_pad($value, 3, ' ', STR_PAD_LEFT);
|
|
|
|
}, $data));
|
2011-07-08 23:25:58 +02:00
|
|
|
}
|
|
|
|
else { // if ($format == 'bin') { default
|
2011-07-13 00:19:05 +02:00
|
|
|
$bin = array();
|
|
|
|
foreach ($data as $byte) {
|
|
|
|
$bin[] = str_pad(decbin($byte >> 4), 4, '0', STR_PAD_LEFT); // high nipple
|
|
|
|
$bin[] = str_pad(decbin($byte & 0x0f), 4, '0', STR_PAD_LEFT); // low nipple
|
|
|
|
}
|
|
|
|
return implode(' ', $bin);
|
2011-07-08 23:25:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
?>
|