Fix unused label issues
Treat labels which are used only by directives in other labels as used if the other label itself is used by an opcode: that is, propagate the transitive usage of labels. Fixes #35
This commit is contained in:
parent
69bfef015f
commit
461e6110ef
101
lib/asm.js
101
lib/asm.js
|
@ -23,6 +23,7 @@
|
|||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
(function () {
|
||||
var _ = require('underscore-node');
|
||||
var tabsRe = /\t/g;
|
||||
|
||||
function expandTabs(line) {
|
||||
|
@ -35,35 +36,91 @@
|
|||
});
|
||||
}
|
||||
|
||||
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].*/;
|
||||
|
||||
function findUsedLabels(asmLines, filterDirectives) {
|
||||
var labelsUsed = {};
|
||||
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) {
|
||||
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);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 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 = {};
|
||||
var labelFind = /[.a-zA-Z0-9_][a-zA-Z0-9$_.]*/g;
|
||||
var files = {};
|
||||
var labelsUsed = findUsedLabels(asmLines, filters.directives);
|
||||
var files = parseFiles(asmLines);
|
||||
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].*/;
|
||||
asmLines.forEach(function (line) {
|
||||
if (line === "" || line[0] === ".") return;
|
||||
var match = line.match(labelFind);
|
||||
if (match && (!filters.directives || 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;
|
||||
});
|
||||
}
|
||||
match = line.match(fileFind);
|
||||
if (match) {
|
||||
files[parseInt(match[1])] = match[2];
|
||||
}
|
||||
});
|
||||
|
||||
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) {
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
"nopt": "3.0.x",
|
||||
"serve-favicon": "2.3.x",
|
||||
"serve-static": "1.10.x",
|
||||
"temp": "0.8.x"
|
||||
"temp": "0.8.x",
|
||||
"underscore-node": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"supervisor": "0.3.1",
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
.file "example.cpp"
|
||||
.intel_syntax noprefix
|
||||
.text
|
||||
.Ltext0:
|
||||
.globl s_sA
|
||||
.section .rodata
|
||||
.LC0:
|
||||
.string "hello world!"
|
||||
.data
|
||||
.align 8
|
||||
.type s_sA, @object
|
||||
.size s_sA, 8
|
||||
s_sA:
|
||||
.quad .LC0
|
||||
.section .rodata
|
||||
.align 8
|
||||
.type s_sB, @object
|
||||
.size s_sB, 10
|
||||
s_sB:
|
||||
.string "hey there"
|
||||
.text
|
||||
.globl main
|
||||
.type main, @function
|
||||
main:
|
||||
.LFB0:
|
||||
.file 1 "/tmp/gcc-explorer-compiler116820-58-ewfj5u/example.cpp"
|
||||
.loc 1 6 0
|
||||
.cfi_startproc
|
||||
push rbp
|
||||
.cfi_def_cfa_offset 16
|
||||
.cfi_offset 6, -16
|
||||
mov rbp, rsp
|
||||
.cfi_def_cfa_register 6
|
||||
.loc 1 7 0
|
||||
mov rax, QWORD PTR s_sA[rip]
|
||||
mov rdi, rax
|
||||
call puts
|
||||
.loc 1 8 0
|
||||
mov edi, OFFSET FLAT:s_sB
|
||||
call puts
|
||||
.loc 1 9 0
|
||||
mov eax, 0
|
||||
pop rbp
|
||||
.cfi_def_cfa 7, 8
|
||||
ret
|
||||
.cfi_endproc
|
|
@ -0,0 +1,17 @@
|
|||
.LC0:
|
||||
.string "hello world!"
|
||||
s_sA:
|
||||
.quad .LC0
|
||||
s_sB:
|
||||
.string "hey there"
|
||||
main:
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
mov rax, QWORD PTR s_sA[rip]
|
||||
mov rdi, rax
|
||||
call puts
|
||||
mov edi, OFFSET FLAT:s_sB
|
||||
call puts
|
||||
mov eax, 0
|
||||
pop rbp
|
||||
ret
|
|
@ -68,7 +68,6 @@ function testFilter(filename, suffix, filters, withSource) {
|
|||
assertEq(file[i], lineExpected, expected + ":" + (i + 1));
|
||||
}
|
||||
}
|
||||
|
||||
cases.forEach(function (x) {
|
||||
testFilter(x, "", {})
|
||||
});
|
||||
|
@ -91,4 +90,5 @@ cases.forEach(function (x) {
|
|||
|
||||
if (failures) {
|
||||
console.log(failures + " failures");
|
||||
process.exit(1);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue