|
|
|
@ -23,6 +23,7 @@
|
|
|
|
|
// POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
|
|
(function () {
|
|
|
|
|
var _ = require('underscore-node');
|
|
|
|
|
var tabsRe = /\t/g;
|
|
|
|
|
|
|
|
|
|
function expandTabs(line) {
|
|
|
|
@ -35,35 +36,91 @@
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function processAsm(asm, filters) {
|
|
|
|
|
if (filters.binary) return processBinaryAsm(asm, filters);
|
|
|
|
|
var labelFind = /[.a-zA-Z_][a-zA-Z0-9$_.]*/g;
|
|
|
|
|
var dataDefn = /\.(string|asciz|ascii|[1248]?byte|short|word|long|quad|value|zero)/;
|
|
|
|
|
var fileFind = /^\s*\.file\s+(\d+)\s+"([^"]+)".*/;
|
|
|
|
|
var hasOpcode = /^\s*([a-zA-Z$_][a-zA-Z0-9$_.]*:\s*)?[a-zA-Z].*/;
|
|
|
|
|
var labelDef = /^([.a-zA-Z_][a-zA-Z0-9$_.]+):/;
|
|
|
|
|
var hasOpcode = /^\s*([a-zA-Z$_][a-zA-Z0-9$_.]*:\s*)?[a-zA-Z].*/;
|
|
|
|
|
|
|
|
|
|
var result = [];
|
|
|
|
|
var asmLines = asm.split("\n");
|
|
|
|
|
function findUsedLabels(asmLines, filterDirectives) {
|
|
|
|
|
var labelsUsed = {};
|
|
|
|
|
var labelFind = /[.a-zA-Z0-9_][a-zA-Z0-9$_.]*/g;
|
|
|
|
|
var files = {};
|
|
|
|
|
var prevLabel = "";
|
|
|
|
|
var dataDefn = /\.(string|asciz|ascii|[1248]?byte|short|word|long|quad|value|zero)/;
|
|
|
|
|
var fileFind = /^\s*\.file\s+(\d+)\s+"([^"]+)".*/;
|
|
|
|
|
var hasOpcode = /^\s*([a-zA-Z0-9$_][a-zA-Z0-9$_.]*:\s*)?[a-zA-Z].*/;
|
|
|
|
|
var weakUsages = {};
|
|
|
|
|
var currentLabel = "";
|
|
|
|
|
|
|
|
|
|
// Scan through looking for definite label usages (ones used by opcodes),
|
|
|
|
|
// and ones that are weakly used: that is, their use is conditional on another label.
|
|
|
|
|
// For example:
|
|
|
|
|
// .foo: .string "moo"
|
|
|
|
|
// .baz: .quad .foo
|
|
|
|
|
// mov eax, .baz
|
|
|
|
|
// In this case, the '.baz' is used by an opcode, and so is strongly used.
|
|
|
|
|
// The '.foo' is weakly used by .baz.
|
|
|
|
|
asmLines.forEach(function (line) {
|
|
|
|
|
if (line === "" || line[0] === ".") return;
|
|
|
|
|
var match = line.match(labelFind);
|
|
|
|
|
if (match && (!filters.directives || line.match(hasOpcode))) {
|
|
|
|
|
var match = line.match(labelDef);
|
|
|
|
|
if (match)
|
|
|
|
|
currentLabel = match[1];
|
|
|
|
|
if (!line || line[0] === '.') return;
|
|
|
|
|
|
|
|
|
|
match = line.match(labelFind);
|
|
|
|
|
if (!match) return;
|
|
|
|
|
|
|
|
|
|
if (!filterDirectives || line.match(hasOpcode)) {
|
|
|
|
|
// Only count a label as used if it's used by an opcode, or else we're not filtering directives.
|
|
|
|
|
match.forEach(function (label) {
|
|
|
|
|
labelsUsed[label] = true;
|
|
|
|
|
});
|
|
|
|
|
} else if (currentLabel) {
|
|
|
|
|
// Note any "weak" usages by this label; that is, usages that are only
|
|
|
|
|
// interesting if the currentLabel is used by an opcode.
|
|
|
|
|
if (!weakUsages[currentLabel]) weakUsages[currentLabel] = [];
|
|
|
|
|
match.forEach(function (label) {
|
|
|
|
|
weakUsages[currentLabel].push(label);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
match = line.match(fileFind);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Now follow the chains of used labels, marking any weak references they refer
|
|
|
|
|
// to as also used. We iteratively do this until either no new labels are found,
|
|
|
|
|
// or we hit a limit (only here to prevent a pathological case from hanging).
|
|
|
|
|
var MaxLabelIterations = 10;
|
|
|
|
|
for (var iter = 0; iter < MaxLabelIterations; ++iter) {
|
|
|
|
|
var toAdd = [];
|
|
|
|
|
_.each(labelsUsed, function (t, label) {
|
|
|
|
|
_.each(weakUsages[label], function (nowused) {
|
|
|
|
|
if (labelsUsed[nowused]) return;
|
|
|
|
|
toAdd.push(nowused);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
if (!toAdd) break;
|
|
|
|
|
_.each(toAdd, function (label) {
|
|
|
|
|
labelsUsed[label] = true;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return labelsUsed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function parseFiles(asmLines) {
|
|
|
|
|
var files = {};
|
|
|
|
|
asmLines.forEach(function (line) {
|
|
|
|
|
var match = line.match(fileFind);
|
|
|
|
|
if (match) {
|
|
|
|
|
files[parseInt(match[1])] = match[2];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return files;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function processAsm(asm, filters) {
|
|
|
|
|
if (filters.binary) return processBinaryAsm(asm, filters);
|
|
|
|
|
|
|
|
|
|
var result = [];
|
|
|
|
|
var asmLines = asm.split("\n");
|
|
|
|
|
var labelsUsed = findUsedLabels(asmLines, filters.directives);
|
|
|
|
|
var files = parseFiles(asmLines);
|
|
|
|
|
var prevLabel = "";
|
|
|
|
|
|
|
|
|
|
var directive = /^\s*\..*$/;
|
|
|
|
|
var labelDefinition = /^([a-zA-Z0-9$_.]+):/;
|
|
|
|
|
var commentOnly = /^\s*(#|@|\/\/).*/;
|
|
|
|
|
var sourceTag = /^\s*\.loc\s+(\d+)\s+(\d+).*/;
|
|
|
|
|
var stdInLooking = /.*<stdin>|-/;
|
|
|
|
@ -89,7 +146,7 @@
|
|
|
|
|
|
|
|
|
|
if (filters.commentOnly && line.match(commentOnly)) return;
|
|
|
|
|
|
|
|
|
|
match = line.match(labelDefinition);
|
|
|
|
|
match = line.match(labelDef);
|
|
|
|
|
if (match) {
|
|
|
|
|
// It's a label definition.
|
|
|
|
|
if (labelsUsed[match[1]] === undefined) {
|
|
|
|
|