diff --git a/.gitignore b/.gitignore index e69de29..0127b85 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1 @@ +build/** diff --git a/scripts/build.ps1 b/scripts/build.ps1 new file mode 100644 index 0000000..2b301fb --- /dev/null +++ b/scripts/build.ps1 @@ -0,0 +1,30 @@ +$misc = join-path $PSScriptRoot 'helpers/misc.ps1' +. $misc + +$path_root = git rev-parse --show-toplevel +$path_build = join-path $path_root 'build' +$path_scripts = join-path $path_root 'scripts' +$path_source = join-path $path_root 'source' +$path_toolchain = join-path $path_root 'toolchain' + +$path_fasm = join-path $path_toolchain 'fasmw17332' +$path_fasmg = join-path $path_toolchain 'fasmg.kl0e' +$path_fasm2 = join-path $path_toolchain 'fasm2' + +$fasm = join-path $path_fasm 'FASM.EXE' +$fasmg = join-path $path_fasmg 'fasmg.exe' +# $fasm2 = join-path $path_fasm2 "fasmg.exe -iInclude('fasm2.inc')" + +verify-path $path_build +push-location $path_build +function build-hello +{ + $env:include = join-path $path_fasm2 'include' + + $asm_hello = join-path $path_source 'hello.asm' + $exe_hello = 'hello.exe' + + & $fasmg $asm_hello $exe_hello +} +build-hello +pop-location diff --git a/scripts/helpers/incremental_checks.ps1 b/scripts/helpers/incremental_checks.ps1 new file mode 100644 index 0000000..5bd6b28 --- /dev/null +++ b/scripts/helpers/incremental_checks.ps1 @@ -0,0 +1,82 @@ +# This is meant to be used with build.ps1, and is not a standalone script. + +function check-FileForChanges +{ + param( + [Parameter(Mandatory=$true)] + [string]$path_file + ) + + if (-not (Test-Path $path_file -PathType Leaf)) { + Write-Error "The provided path is not a valid file: $path_file" + return $false + } + $file_name = Split-Path $path_file -Leaf + $path_csv = Join-Path $path_build ($file_name + "_file_hash.csv") + + $csv_file_hash = $null + if (Test-Path $path_csv) { + $csv_file_hash = Import-Csv $path_csv | Select-Object -ExpandProperty value + } + + $current_hash_info = Get-FileHash -Path $path_file -Algorithm MD5 + $current_file_hash = $current_hash_info.Hash + + # Save the current hash to the CSV + [PSCustomObject]@{ + name = $path_file + value = $current_file_hash + } | Export-Csv $path_csv -NoTypeInformation + + if ($csv_file_hash -and $csv_file_hash -eq $current_file_hash) { + return $false + } else { + return $true + } +} + +# Check to see if the module has changed files since the last build +function check-ModuleForChanges +{ + param( [string]$path_module, [array]$excludes ) + + $module_name = split-path $path_module -leaf + $path_csv = Join-Path $path_build ("module_" + $module_name + "_hashes.csv") + + $csv_file_hashes = $null + if ( test-path $path_csv ) { + $csv_file_hashes = @{} + import-csv $path_csv | foreach-object { + $csv_file_hashes[ $_.name ] = $_.value + } + } + + $file_hashes = @{} + get-childitem -path $path_module -file -Exclude $excludes -Recurse | foreach-object { + $id = $_.fullname + $hash_info = get-filehash -path $id -Algorithm MD5 + $file_hashes[ $id ] = $hash_info.Hash + } + + $file_hashes.GetEnumerator() | foreach-object { [PSCustomObject]$_ } | + export-csv $path_csv -NoTypeInformation + + if ( -not $csv_file_hashes ) { return $true } + if ( $csv_file_hashes.Count -ne $file_hashes.Count ) { return $true } + + foreach ( $key in $csv_file_hashes.Keys ) { + if ( $csv_file_hashes[ $key ] -ne $file_hashes[ $key ] ) { + return $true + } + } + return $false +} + +function mark-ModuleDirty { + param( [string]$path_module ) + + $module_name = split-path $path_module -leaf + $path_csv = Join-Path $path_build ("module_" + $module_name + "_hashes.csv") + + remove-item -Force -Path $path_csv +} diff --git a/scripts/helpers/ini.ps1 b/scripts/helpers/ini.ps1 new file mode 100644 index 0000000..25d20b2 --- /dev/null +++ b/scripts/helpers/ini.ps1 @@ -0,0 +1,20 @@ +# This is meant to be used with build.ps1, and is not a standalone script. + +function Get-IniContent { param([ string]$filePath ) + $ini = @{} + $currentSection = $null + switch -regex -file $filePath + { + "^\[(.+)\]$" { + $currentSection = $matches[1].Trim() + $ini[$currentSection] = @{} + } + "^(.+?)\s*=\s*(.*)" { + $key, $value = $matches[1].Trim(), $matches[2].Trim() + if ($null -ne $currentSection) { + $ini[$currentSection][$key] = $value + } + } + } + return $ini +} diff --git a/scripts/helpers/misc.ps1 b/scripts/helpers/misc.ps1 new file mode 100644 index 0000000..edd09ed --- /dev/null +++ b/scripts/helpers/misc.ps1 @@ -0,0 +1,67 @@ +function clone-gitrepo { param( [string] $path, [string] $url ) + if (test-path $path) { + # git -C $path pull + } + else { + Write-Host "Cloning $url ..." + git clone $url $path + } +} + +function Update-GitRepo +{ + param( [string] $path, [string] $url, [string] $build_command ) + + if ( $build_command -eq $null ) { + write-host "Attempted to call Update-GitRepo without build_command specified" + return + } + + $repo_name = $url.Split('/')[-1].Replace('.git', '') + + $last_built_commit = join-path $path_build "last_built_commit_$repo_name.txt" + if ( -not(test-path -Path $path)) + { + write-host "Cloining repo from $url to $path" + git clone $url $path + + write-host "Building $url" + push-location $path + & "$build_command" + pop-location + + git -C $path rev-parse HEAD | out-file $last_built_commit + $script:binaries_dirty = $true + write-host + return + } + + git -C $path fetch + $latest_commit_hash = git -C $path rev-parse '@{u}' + $last_built_hash = if (Test-Path $last_built_commit) { Get-Content $last_built_commit } else { "" } + + if ( $latest_commit_hash -eq $last_built_hash ) { + write-host + return + } + + write-host "Build out of date for: $path, updating" + write-host 'Pulling...' + git -C $path pull + + write-host "Building $url" + push-location $path + & $build_command + pop-location + + $latest_commit_hash | out-file $last_built_commit + $script:binaries_dirty = $true + write-host +} + +function verify-path { param( $path ) + if (test-path $path) {return} + + new-item -ItemType Directory -Path $path + return +} diff --git a/source/hello.asm b/source/hello.asm new file mode 100644 index 0000000..80480fa --- /dev/null +++ b/source/hello.asm @@ -0,0 +1,38 @@ +include 'fasm2.inc' + +format PE64 console +entry main + +section '.data' data readable writeable + message db 'Hello World!', 13, 10 + message_len = $ - message + written dq ? + +section '.text' code readable executable +main: + sub rsp, 40 ; 32 + 8 for alignment + + mov ecx, -11 ; STD_OUTPUT_HANDLE + call [GetStdHandle] + + mov rcx, rax ; Handle + lea rdx, [message] ; Buffer + mov r8, message_len ; Length + lea r9, [written] ; Bytes written + push 0 ; Reserved parameter + sub rsp, 32 ; Shadow space + call [WriteConsoleA] + add rsp, 40 ; Cleanup stack + reserved param + + xor ecx, ecx ; Exit code 0 + call [ExitProcess] + +section '.idata' import data readable + library kernel32,'KERNEL32.DLL' + +include 'win64a.inc' + +import kernel32,\ + GetStdHandle,'GetStdHandle',\ + WriteConsoleA,'WriteConsoleA',\ + ExitProcess,'ExitProcess'