Improve .incbin to let its arguments be arbitrary expressions

This introduces a new IR node for mutable-during-assembly ranges.
In the common case, where offset and range are hardcoded or missing,
it continues with the older, more efficient behavior.
This commit is contained in:
Michael Martin 2012-06-03 23:50:29 -07:00
parent 9ea0962e52
commit 9323067e91
2 changed files with 42 additions and 8 deletions

View File

@ -53,26 +53,43 @@ def pragmaRequire(ppt, line, result):
def pragmaIncbin(ppt, line, result):
"Includes a binary file"
filename = line.expect("STRING").value
offset = 0
size = -1
offset = IR.ConstantExpr(0)
size = None
if str(line.lookahead(0)) == ",":
line.pop()
offset = line.expect("NUM").value
offset = FE.parse_expr(line)
if str(line.lookahead(0)) == ",":
line.pop()
size = line.expect("NUM").value
size = FE.parse_expr(line)
line.expect("EOL")
if type(filename) == str:
try:
f = file(os.path.join(FE.context_directory, filename), "rb")
f.seek(offset)
bytes = f.read(size)
if offset.hardcoded and (size is None or size.hardcoded):
# We know how big it will be, we can just use the values.
if size is None:
size = IR.ConstantExpr(-1)
f.seek(offset.value())
bytes = f.read(size.value())
bytes = [IR.ConstantExpr(ord(x)) for x in bytes]
result.append(IR.Node(ppt, "Byte", *bytes))
else:
# offset or length could change based on label placement.
# This seems like an unbelievably bad idea, but since we
# don't have constant prop it will happen for any symbolic
# alias. Don't use symbolic aliases when extracting tiny
# pieces out of humongous files, I guess.
bytes = f.read()
bytes = [IR.ConstantExpr(ord(x)) for x in bytes]
if size is None:
size = IR.SequenceExpr([IR.ConstantExpr(len(bytes)),
"-",
offset])
result.append(IR.Node(ppt, "ByteRange", offset, size, *bytes))
f.close()
except IOError:
Err.log("Could not read " + filename)
return
bytes = [IR.ConstantExpr(ord(x)) for x in bytes]
result.append(IR.Node(ppt, "Byte", *bytes))
def pragmaCharmap(ppt, line, result):

View File

@ -366,6 +366,10 @@ class PCTracker(Pass):
def visitByte(self, node, env):
env.incPC(len(node.data))
def visitByteRange(self, node, env):
if node.data[1].valid(env):
env.incPC(node.data[1].value(env))
def visitWord(self, node, env):
env.incPC(len(node.data) * 2)
@ -744,6 +748,19 @@ class Assembler(Pass):
env.incPC(len(node.data))
self.data += len(node.data)
def visitByteRange(self, node, env):
offset = node.data[0].value(env) + 2
length = node.data[1].value(env)
if offset < 2:
Err.log("Negative offset in .incbin")
elif offset + length > len(node.data):
Err.log("File too small for .incbin subrange")
else:
for expr in node.data[offset:(offset + length)]:
self.outputbyte(expr, env)
env.incPC(length)
self.data += length
def visitWord(self, node, env):
for expr in node.data:
self.outputword(expr, env)