Permalink
Browse files

Much closer to getting conditionals to work. CodeStream now understan…

…ds labels, which do not have to be defined when referenced, allowing one-pass compilation. The address to compile to is now kept track of. CodeStream can now assemble jmp and jcc instructions. The ability to disassemble jmp and jcc instructions is underway.
  • Loading branch information...
martinmcclure committed Sep 29, 2012
1 parent a145f18 commit 2c760bcabc054e6fcbb8520155893eb545f96548
Showing with 352 additions and 39 deletions.
  1. +1 −0 packages/Mist.package/ElfFile.class/instance/entryAddress..st
  2. +1 −1 packages/Mist.package/ElfFile.class/instance/writeElfHeader.st
  3. +1 −1 packages/Mist.package/ElfFile.class/instance/writeProgramHeaderTable.st
  4. +3 −3 packages/Mist.package/ElfFile.class/methodProperties.json
  5. +1 −1 packages/Mist.package/FogTests.class/class/isB.st
  6. +7 −0 packages/Mist.package/FogTests.class/instance/cleanupForExecutable..st
  7. +0 −1 packages/Mist.package/FogTests.class/instance/compile.andRun.stdin..st
  8. +5 −3 packages/Mist.package/FogTests.class/instance/compile.andWriteTo..st
  9. +2 −1 packages/Mist.package/FogTests.class/instance/compileAndRun.withInput.expectingOutput..st
  10. +5 −4 packages/Mist.package/FogTests.class/methodProperties.json
  11. +4 −0 packages/Mist.package/FogX64Compiler.class/instance/startAddress..st
  12. +3 −0 packages/Mist.package/FogX64Compiler.class/instance/startAddress.st
  13. +2 −0 packages/Mist.package/FogX64Compiler.class/methodProperties.json
  14. +2 −1 packages/Mist.package/FogX64Compiler.class/properties.json
  15. +1 −1 packages/Mist.package/FogX64ConditionalNode.class/instance/childLabels.st
  16. +1 −1 packages/Mist.package/FogX64ConditionalNode.class/instance/label.st
  17. +14 −0 packages/Mist.package/FogX64ConditionalNode.class/instance/pass1InOrderChildClobbered..st
  18. +21 −0 packages/Mist.package/FogX64ConditionalNode.class/instance/pass2CompileOn..st
  19. +3 −1 packages/Mist.package/FogX64ConditionalNode.class/methodProperties.json
  20. +8 −0 packages/Mist.package/X64CodeLabel.class/README.md
  21. +3 −0 packages/Mist.package/X64CodeLabel.class/instance/addReference..st
  22. +4 −0 packages/Mist.package/X64CodeLabel.class/instance/initialize.st
  23. +3 −0 packages/Mist.package/X64CodeLabel.class/instance/isResolved.st
  24. +7 −0 packages/Mist.package/X64CodeLabel.class/instance/resolveTo..st
  25. +8 −0 packages/Mist.package/X64CodeLabel.class/methodProperties.json
  26. +15 −0 packages/Mist.package/X64CodeLabel.class/properties.json
  27. +7 −0 packages/Mist.package/X64CodeStream.class/README.md
  28. +6 −0 packages/Mist.package/X64CodeStream.class/class/initialize.st
  29. +26 −0 packages/Mist.package/X64CodeStream.class/class/initializeConditionCodes.st
  30. +2 −1 packages/Mist.package/X64CodeStream.class/instance/compiler..st
  31. +5 −0 packages/Mist.package/X64CodeStream.class/instance/currentAddress.st
  32. +2 −1 packages/Mist.package/X64CodeStream.class/instance/initialize.st
  33. +12 −0 packages/Mist.package/X64CodeStream.class/instance/jcc.to..st
  34. +9 −0 packages/Mist.package/X64CodeStream.class/instance/jmpIfNot.to..st
  35. +11 −0 packages/Mist.package/X64CodeStream.class/instance/jmpTo..st
  36. +3 −0 packages/Mist.package/X64CodeStream.class/instance/label..st
  37. +3 −0 packages/Mist.package/X64CodeStream.class/instance/labelAt..st
  38. +9 −0 packages/Mist.package/X64CodeStream.class/instance/relativeRef32To..st
  39. +12 −3 packages/Mist.package/X64CodeStream.class/methodProperties.json
  40. +5 −3 packages/Mist.package/X64CodeStream.class/properties.json
  41. +6 −0 packages/Mist.package/X64CodeUnresolvedReference.class/README.md
  42. +3 −0 packages/Mist.package/X64CodeUnresolvedReference.class/class/code.address..st
  43. +6 −0 packages/Mist.package/X64CodeUnresolvedReference.class/instance/code.address..st
  44. +3 −0 packages/Mist.package/X64CodeUnresolvedReference.class/instance/resolveTo..st
  45. +6 −0 packages/Mist.package/X64CodeUnresolvedReference.class/methodProperties.json
  46. +16 −0 packages/Mist.package/X64CodeUnresolvedReference.class/properties.json
  47. +3 −0 packages/Mist.package/X64CodeUnresolvedRelative32Reference.class/README.md
  48. +18 −0 packages/Mist.package/X64CodeUnresolvedRelative32Reference.class/instance/resolveTo..st
  49. +5 −0 packages/Mist.package/X64CodeUnresolvedRelative32Reference.class/methodProperties.json
  50. +14 −0 packages/Mist.package/X64CodeUnresolvedRelative32Reference.class/properties.json
  51. +3 −0 packages/Mist.package/X64DisassemblerOpcodeMap.class/instance/at.putMnemonic..st
  52. 0 ...64DisassemblerOpcodeMapPrimary.class → X64DisassemblerOpcodeMap.class}/instance/from.to.by.do..st
  53. +3 −1 packages/Mist.package/X64DisassemblerOpcodeMap.class/methodProperties.json
  54. +0 −1 packages/Mist.package/X64DisassemblerOpcodeMapPrimary.class/methodProperties.json
  55. +20 −4 packages/Mist.package/X64DisassemblerOpcodeMapSecondary.class/instance/initialize.st
  56. +1 −1 packages/Mist.package/X64DisassemblerOpcodeMapSecondary.class/methodProperties.json
  57. +6 −3 packages/Mist.package/X64DisassemblerTests.class/instance/compileAndDisassemble..st
  58. +1 −1 packages/Mist.package/X64DisassemblerTests.class/methodProperties.json
  59. +1 −1 packages/Mist.package/monticello.meta/version
@@ -1,3 +1,4 @@
accessing
entryAddress: anObject
"The address to start executing after loading"
entryAddress := anObject
@@ -5,7 +5,7 @@ writeElfHeader
write2: 2; "type executable"
write2: 62; "machine: x86_64"
write4: 1; "current version"
write8: entryAddress + 64 + 56;
write8: entryAddress; "the address to start executing code"
write8: 64; "program header table immediately follows this header"
write8: 0; "section header table offset, none in this case"
write4: 0; "processor-specific flags. I don't know what's supposed to be here."
@@ -4,7 +4,7 @@ writeProgramHeaderTable
self write4: 1; "Loadable segment"
write4: 7; "rwx permissions"
write8: 0; "offset of segment from start of file"
write8: entryAddress; "where to load the segment in virtual memory"
write8: entryAddress - 64 - 56; "where to load the segment in virtual memory -- the code start address less the size of the headers"
write8: 0; "unused physical address"
write8: segments first size + 64 + 56; "size of segment in file"
write8: 16r100000; "1MiB" "segments first size + 64 + 56;" "size of segment in memory"
@@ -4,16 +4,16 @@
"fortyTwoWithBreak" : "MartinMcClure 8/28/2010 13:53" },
"instance" : {
"addSegment:" : "MartinMcClure 8/18/2010 15:10",
"entryAddress:" : "MartinMcClure 8/16/2010 11:32",
"entryAddress:" : "MartinMcClure 9/28/2012 21:02",
"initialize" : "MartinMcClure 8/16/2010 11:49",
"write" : "MartinMcClure 8/16/2010 11:45",
"write1:" : "MartinMcClure 8/16/2010 11:20",
"write2:" : "MartinMcClure 8/16/2010 11:29",
"write4:" : "MartinMcClure 8/18/2010 15:15",
"write8:" : "MartinMcClure 8/18/2010 15:15",
"writeElfHeader" : "MartinMcClure 8/19/2010 07:57",
"writeElfHeader" : "MartinMcClure 9/28/2012 21:04",
"writeIdent" : "MartinMcClure 8/18/2010 15:22",
"writeProgramHeaderTable" : "MartinMcClure 11/5/2011 08:59",
"writeProgramHeaderTable" : "MartinMcClure 9/28/2012 21:03",
"writeSegments" : "MartinMcClure 8/16/2010 11:12",
"writeString:" : "MartinMcClure 8/16/2010 11:21",
"writeToFileNamed:" : "tfel 9/6/2012 15:49",
@@ -6,7 +6,7 @@ isB
^ Fog
program:
{"(Fog breakpoint)."
{(Fog breakpoint).
(Fog
variableScope:
{'termiosPtr'.
@@ -0,0 +1,7 @@
support
cleanupForExecutable: filename
FileDirectory default
deleteFileNamed: filename;
deleteFileNamed: filename , '.stdin';
deleteFileNamed: filename , '.stdout';
deleteFileNamed: filename , '.stdErr'
@@ -3,5 +3,4 @@ compile: program andRun: filename stdin: stdin
| process |
self compile: program andWriteTo: filename.
process := self execute: filename withStdin: stdin.
FileDirectory default deleteFileNamed: filename.
^ process
@@ -2,10 +2,12 @@ support
compile: program andWriteTo: filename
"Compile the given Fog program and write it to an ELF file with the given name."
| elfFile seg nativeCode |
nativeCode := FogX64Compiler new compile: program.
| compiler elfFile seg nativeCode |
compiler := FogX64Compiler new.
compiler startAddress: 16r00400078.
nativeCode := compiler compile: program.
elfFile := ElfFile new.
elfFile entryAddress: 16r00400000. "default"
elfFile entryAddress: compiler startAddress.
seg := ElfSegment new.
seg bytes: nativeCode.
elfFile addSegment: seg.
@@ -13,4 +13,5 @@ compileAndRun: program withInput: providedString expectingOutput: expectedString
reset;
upToEnd)
equals: expectedString.
self assert: process exitStatus \\ 256 equals: 0
self assert: process exitStatus \\ 256 equals: 0.
self cleanupForExecutable: filename
@@ -3,16 +3,17 @@
"consume1" : "MartinMcClure 9/13/2012 17:09",
"echo1" : "MartinMcClure 9/13/2012 17:07",
"fortyTwo" : "MartinMcClure 9/13/2012 17:05",
"isB" : "MartinMcClure 9/22/2012 16:55",
"isB" : "MartinMcClure 9/28/2012 22:53",
"print7" : "MartinMcClure 9/13/2012 17:03",
"printH" : "MartinMcClure 9/13/2012 17:01",
"threePlusFour" : "MartinMcClure 9/13/2012 16:58" },
"instance" : {
"compile:andRun:stdin:" : "tfel 9/6/2012 16:28",
"compile:andWriteTo:" : "MartinMcClure 9/22/2012 14:31",
"cleanupForExecutable:" : "MartinMcClure 9/28/2012 22:57",
"compile:andRun:stdin:" : "MartinMcClure 9/28/2012 22:58",
"compile:andWriteTo:" : "MartinMcClure 9/28/2012 21:11",
"compileAndRun:" : "tfel 9/6/2012 16:27",
"compileAndRun:stdin:" : "tfel 9/6/2012 16:25",
"compileAndRun:withInput:expectingOutput:" : "MartinMcClure 9/17/2012 10:38",
"compileAndRun:withInput:expectingOutput:" : "MartinMcClure 9/28/2012 22:58",
"execute:withStdin:" : "tfel 9/12/2012 16:34",
"tearDown" : "tfel 9/6/2012 16:04",
"testConsume1" : "MartinMcClure 9/13/2012 17:10",
@@ -0,0 +1,4 @@
accessing
startAddress: anInteger
"The address at which the first byte of compiled code is intended to be placed."
startAddress := anInteger
@@ -0,0 +1,3 @@
accessing
startAddress
^ startAddress
@@ -11,5 +11,7 @@
"popScope" : "MartinMcClure 12/25/2010 19:10",
"pushScope:" : "MartinMcClure 12/25/2010 10:16",
"registersDo:" : "MartinMcClure 6/18/2011 08:31",
"startAddress" : "MartinMcClure 9/28/2012 21:08",
"startAddress:" : "MartinMcClure 9/28/2012 21:09",
"usingLocation:" : "MartinMcClure 12/30/2010 18:55",
"variableNamed:" : "MartinMcClure 12/30/2010 14:38" } }
@@ -10,7 +10,8 @@
"codeStream",
"stackTempsUsed",
"scopeStack",
"stackTemps" ],
"stackTemps",
"startAddress" ],
"name" : "FogX64Compiler",
"pools" : [
],
@@ -1,4 +1,4 @@
printing
portable-printing
childLabels
^ {('if ' , flagSymbol).
'then'.
@@ -1,3 +1,3 @@
printing
portable-printing
label
^ 'Conditional'
@@ -0,0 +1,14 @@
x64-compiling-pass1
pass1InOrderChildClobbered: childClobbered
"Since I consume the value of child 1 before 2 or 3 execute, and only one of 2 or 3 execute,
none of my children need consider any locations siblingClobbered. However, all locations used
by any of my children need to be considered clobbered as far as *my* siblings are concerned,
so must put the union of those locations in the childClobbered passed to me."
children size to: 1 by: -1 do: [ :i |
| childVar thisChildClobbered |
childVar := children at: i.
thisChildClobbered := ClobberedSet compiler: compiler.
childVar child pass1CompileWith: compiler siblingClobbered: thisChildClobbered.
childClobbered addAll: thisChildClobbered.
self assignInputVariableNumber: i ]
@@ -0,0 +1,21 @@
x64-compiling-pass2
pass2CompileOn: codeStream
"Code emitted looks like this:
<child1>
Jcc elseLabel
<child2>
JMP finalLabel
elseLabel <child3>
finalLabel "
| elseLabel finalLabel |
elseLabel := 'elseLabel' copy.
finalLabel := 'finalLabel' copy.
(children at: 1) child pass2CompileOn: codeStream.
codeStream jmpIfNot: flagSymbol to: elseLabel.
(children at: 2) child pass2CompileOn: codeStream.
codeStream
jmpTo: finalLabel;
label: elseLabel.
(children at: 3) child pass2CompileOn: codeStream.
codeStream label: finalLabel
@@ -6,4 +6,6 @@
"childLabels" : "MartinMcClure 9/22/2012 10:01",
"flagSymbol:" : "MartinMcClure 9/21/2012 20:13",
"hasSideEffects" : "MartinMcClure 9/22/2012 17:01",
"label" : "MartinMcClure 9/22/2012 10:01" } }
"label" : "MartinMcClure 9/22/2012 10:01",
"pass1InOrderChildClobbered:" : "MartinMcClure 9/28/2012 19:20",
"pass2CompileOn:" : "MartinMcClure 9/28/2012 19:49" } }
@@ -0,0 +1,8 @@
An X64CodeLabel is used by the Mist x86_64 assembler, X64CodeStream.
It may be resolved (if its address is known) or unresolved.
If unresolved, address is #unresolved.
If resolved, unresolvedReferences is #resolved
Instance Variables:
address <Symbol | integer>
unresolvedReferences <Set of X64CodeUnresolvedReference | Symbol>
@@ -0,0 +1,3 @@
public
addReference: reference
unresolvedReferences add: reference
@@ -0,0 +1,4 @@
initialize-release
initialize
address := #unresolved.
unresolvedReferences := Set new
@@ -0,0 +1,3 @@
testing
isResolved
^ address ~~ #unresolved
@@ -0,0 +1,7 @@
public
resolveTo: addressInteger
self isResolved
ifTrue: [ self error: 'Attempt to resolve already-resolved label' ].
address := addressInteger.
unresolvedReferences do: [ :each | each resolveTo: address ].
unresolvedReferences := #resolved
@@ -0,0 +1,8 @@
{
"class" : {
},
"instance" : {
"addReference:" : "MartinMcClure 9/28/2012 22:41",
"initialize" : "MartinMcClure 9/28/2012 21:24",
"isResolved" : "MartinMcClure 9/28/2012 22:16",
"resolveTo:" : "MartinMcClure 9/28/2012 21:28" } }
@@ -0,0 +1,15 @@
{
"category" : "Mist",
"classinstvars" : [
],
"classvars" : [
],
"commentStamp" : "MartinMcClure 9/28/2012 21:28",
"instvars" : [
"address",
"unresolvedReferences" ],
"name" : "X64CodeLabel",
"pools" : [
],
"super" : "Object",
"type" : "normal" }
@@ -0,0 +1,7 @@
An X64CodeStream is effectively an assembler from messages, one per instruction or label, to machine code bytes output on the output stream.
Instance Variables:
compiler <FogX64Compiler > The compiler that's using me
output <LittleEndianByteStream> The stream of output bytes
startAddress <Integer> The machine address that my first output byte will be at when it is executed.
labels <IdentityDictionary of Object -> X64CodeLabel> The client identifies each label with an arbitrary unique object.
@@ -0,0 +1,6 @@
class initialization
initialize
"X64CodeStream initialize"
self initializeConditionCodes
@@ -0,0 +1,26 @@
class initialization
initializeConditionCodes
"The condition codes are the lower 4 bits of the opcodes for a Jcc on that condition.
ConditionCodes is an IdentityDictionary mapping the condition symbols to those condition codes."
ConditionCodes := IdentityDictionary new.
ConditionCodes
at: #O put: 0;
at: #NO put: 1;
at: #B put: 2;
at: #C put: 2;
at: #NC put: 3;
at: #AE put: 3;
at: #Z put: 4;
at: #NZ put: 5;
at: #BE put: 6;
at: #A put: 7;
at: #S put: 8;
at: #NS put: 9;
at: #PE put: 10;
at: #PO put: 11;
at: #L put: 12;
at: #GE put: 13;
at: #LE put: 14;
at: #G put: 15
@@ -1,3 +1,4 @@
private-accessing
compiler: aCompiler
compiler := aCompiler
compiler := aCompiler.
startAddress := aCompiler startAddress
@@ -0,0 +1,5 @@
helpers
currentAddress
"What is the machine address of the next byte I will output?"
^ startAddress + output position
@@ -1,3 +1,4 @@
initialize-release
initialize
output := LittleEndianByteStream on: ByteArray new
output := LittleEndianByteStream on: ByteArray new.
labels := IdentityDictionary new
@@ -0,0 +1,12 @@
helpers
jcc: conditionCode to: labelId
"conditionCode is the low-order four bits of the opcode.
If the condition is met jump to the label with the given ID."
"Jcc rel32off 0F 80 cd"
| label |
output
nextPut: 16r0F;
nextPut: 16r80 + conditionCode.
self relativeRef32To: labelId
@@ -0,0 +1,9 @@
instructions
jmpIfNot: flagSymbol to: labelId
"If the condition specified by flagSymbol is *not* true, jump to the label with the given ID object."
| conditionCode |
"Xor-ing with 1 flips the bottom bit, negating the sense"
conditionCode := (ConditionCodes at: flagSymbol) bitXor: 1.
self jcc: conditionCode to: labelId
@@ -0,0 +1,11 @@
instructions
jmpTo: labelId
"Unconditionally jump to the label with the given ID object."
"JMP rel32off E9 cd Near jump with the target specified by a 32-bit signed displacement."
| label |
output
nextPut: 16rE9.
self relativeRef32To: labelId
@@ -0,0 +1,3 @@
labels
label: idObject
(self labelAt: idObject) resolveTo: self currentAddress
@@ -0,0 +1,3 @@
private-accessing
labelAt: idObject
^ labels at: idObject ifAbsentPut: X64CodeLabel new
@@ -0,0 +1,9 @@
helpers
relativeRef32To: labelId
| label |
label := self labelAt: labelId.
label isResolved
ifTrue: [ output write4s: self currentAddress + 4 - label address ]
ifFalse: [
label addReference: (X64CodeUnresolvedRelative32Reference code: output address: self currentAddress).
output write4: 0 ]
Oops, something went wrong.

0 comments on commit 2c760bc

Please sign in to comment.