NewASM Virtual Machine – simulates a computer with its own complex assembly language and compiler; NewASM is a low-level programming language which combines explicit memory and register control, giving it a breeze of assembly-like feel, with high-level functionalities such as objects, threads with many functionalities and many more.
Aim is to create a sealed development environment used for creating platform-independent applications!
#NewASM
279 messages · Page 1 of 1 (latest)
🔥
New major update with many many features.
Prone to bugs!
Added namespaces and I/O ports for the virtual disk!
Includes optimisation and bug-fixes under the hood
Added tuples and bug fixes
- Boosted performance with inlined bytecode compiler
- Added the register dereferencing operator
Drop a star if you like the project 🖤 :D
interpreting asm? why someone would use that, if it creates a layer of abstraction?
- Added thread channels.
- Syntax rework.
Well, abstraction is something relative. What is abstract on our CPUs, cannot be abstract on a virtual machine.
My goal was to make a low level assembly-like language that could be written only once and ran on any machine through the virtual machine and the shell.
The only big abstractions are namespaces, lambda procedures and objects.
But since this is a VM emulating a complex virtual CPU architecture, we cannot call these abstractions as NewASM is supposed to be the “machine code” of its own VM :D
My second project goal was to create a C compiler that compiles C code into NewASM code.
So technically, NewASM would essentially become a little platform.
As you can see, the VM can run on any Linux or Windows version (I tested it on Vista too), seamlessly, so you can basically look at it as a platform-independent standard for assembly
So yeah, this is my reasoning
Please note that the system is currently under heavy development, and that many things are actually prototypes
In build 7 I’ll do a complete memory rework and implement C-like types, allocation and real pointers!
Complete backend rework
C-like memory
New tcp and http kernel modules
Give a star if you find the project interesting! :D
it's an assembly language that's interpreted?
Yes,
but the docs are very outdated
at this scale, it is now a vm with its own crazy hardware implementations
hardware implementation?
simulation*
hardware simulation? that just sounds like a VM
so it has nothing to do with hardware
like what
lol
currently, im shifting it to bytecode thing
so yh
something like a hybrid between asm and C
so im simplifying the old complex syntax it had
how fast is it on a 'Hello World' program?
uhm
fast enough?
probably a small part of a millisecond
it was doing some tests with python
so it is pretty comparable
it depends on what you are doing
can u try runnin' it with the time command?
BRO 
'Hello World' program?
it already prints execution time after the program finishes
im not on pc
i am talking generally
can you tell me an average time?
1ms ? or 10ms ?
hello world is a bad benchmark
how are u doin' the print? with a syscall?
you saw the readme right?
bro
using "ios"
.data
string text : "Hello world"
intg len : $-text
.start
mov tlr, text
mov stl, 0c1
mov fdx, 1
mov bos, len
sysenter "ios"
syscall
ret 0
sysenter "ios" ?
so what do you see
using "ios"
that is a compile time instruction telling the vm the program is using an ios module
what are these
sysenter “ios” tells the runtime that we are about to call a function inside that module
and syscall calls that function with a specific fdx
this isnt even assembly. when you say 'syscall', youre talking about direct communication with the system so when we say 'sysenter "ios"' which syscall are we actually making?
@waxen dune has reached level 5. GG!
of course it is not assembly you know
you can look at it like a different architecture
mov fdx, .. sets the id
i built my own architecture, my bro I understand everything.
ooh okey
cool!
your assembly language is pretty wild, i m lowkey into it but not gonna lie, Ive got serious doubts about how usable it is or if the syntax even makes sense thats why i m just asking questions for now
i am doubtful about it too
so i am rewriting it
it was awful
it is pretty compared to what it was
nice
https://github.com/bracesoftware/newasm/releases/tag/build8rc3
New release!
- Added a simple “math” library
- Added the volatile decorator
- Added the caching system
- Added the ‘printenv’ shell command
- More optimisation
- Optimisation
- Procedures can now be declared within namespaces
- Primitive classes
- Fixes on the
movasxinstruction
That doesn't sound like asm
it is not asm
Bugfixes!
Bro, try posting on Hacker News, the audience is bigger there and maybe there will be more positive recommendations.
build 18 out after long time
big performance improvements
wiki reworked
Build 27 out, compared to all versions before, this is the most stable and most efficient one yet
How are you so smart? I have no idea how to write on c++ your own assembler..
it's a all about practice and experience
Not working yet, just began learning it, make cli project which asks for number, and asks what is the x² of the number, that's it
@wet lodge has reached level 1. GG!
да
with time comes ease!
we were all at one point just tinkering with std::cout and std::cin
согласен
сугласан
агреед
абсолутели
ванхандрет персент
сэнкью
ай донт андерстанд зис щит
хау донт ју андерстенд
бекас ай эм лэйзи матерфакэр
@storm zinc has reached level 5. GG!
ви ар комјуникејтинг вери изли
вер ар ју фром
аи ем фром босниа
In English please
ви ар талкинг ин инглиш
ор ай донт кноу жуст уз эй транслейтор
ай эм нот даубтинг тиз щит ю ноу?
I asked nicely
ай диднт вантед ту хурт ю, ай эм вери сорэ браза
аххааахахахахаахаха
Well this is awkward... I guess the next step is a mute?
chill man
he is speaking english
but in cyrillc
daaamn, chill
indeed
yu knou zat?
wat?
Guys...
Hello respected moderator!
We are terribly sorry for our behaviour!
https://github.com/bracesoftware/newasm/releases/tag/build30
What's new or changed?
- Added compile-time label name mangling with temporary namespaces. Read more in namespace docs!
- The
.textcode section is now a synonym for.start, since the macros are now purely a compile-time thing. - Macros are now inlined at compile-time.
- Around 5-10% performance improvements.
Fixed issues - Fixed issue #30: compiler wasn't ever reporting any label redefinitions.
- Fixed issue #31: compiler wasn't displaying correct code lines in error messages.
Build 31 is brewing with compile-time logic, better compiler optimizations and kernel/available host services updates
Holyyy
What's new or changed?
- Anonymous functions have been severely improved regarding speed and functionality. Now you can use
callc,retc,loopand such!
.text
thread thisisfun -> {
mov tlr, "this is really fun"
call std::ios::writeln
mov tlr, 908
call std::ios::writeln
mov tlr, 243.4
call std::ios::writeln
mov tlr, (proc)
int 0x3
mov rax, 4
mov tlr, "Hi from lambda in thread\n"
mov fdx, 1
sysenter "ios"
syscall
{:lmao}
syscall
loop rax, lmao
int 0x3
halt 0
(end)
}
As you can see, lambdas in threads now have their own labels because the JIT compiler ignores the sealed labels within the (proc) block.
Another stupid example would be:
.text
mov tlr, (proc)
jmp label2
{:label1}
jmp label3
{:label2}
jmp label1
{:label3}
halt 0
(end)
- The NewASM compiler now allows following compile-time instructions for implementing very simple logic:
ifdef: checks if a symbol/flag is defined;ifndef: checks if a symbol/flag is not defined;fi: used for ending anifblock.
If you want to combine if-statements, just nest them, you don't need to use fi more than once.
def SMTH, 0
ifdef SMTH
ifndef SMTH_ELSE
; do something
fi
There are no else variants, you have to end each if-block with fi.
- Added a new concept of address fetching - a
fetchinstruction! This instruction is used to fetch a procedure or variable pointer, so we can use it with thethiskeyword. This is very important when optimizing your code because the compiler then can generate code that doesn't do any dictionary lookup.
.data
./data
intg variable: 4
./!data
.text
fetch data::variable ; get variable's address
mov this, 6 ; give it a new value
mov tlr, *this ; dereference the this ptr
call std::ios::writeln ; prints 6
As you can see, we look for the variable only once, and then use the pointer, which means we get around 1.75x faster than using the variable's name twice.
We can also fetch addresses of procedures:
.text
fetch std::ios::writeln
mov tlr, "Hello"
call this ; prints Hello
mov tlr, 465
call this
; .. etc
; this is way faster than letting the dispatcher
; look for the procedure every time you use call
; callc is still faster tho
If you don't want a variable to be fetched, use the new @safe attribute.
.data
@safe
intg var: 0
.text
fetch var ; segmentation fault
Fixed issues
- Fixed issue #32.
idk
max 2 years
I started rewriting it just this year i think
So far i have made huge performance improvements
compilation and things got introduced just this year
literally everything has been rewritten in these few months because i started realising how bad the code was
Goddamn
thanks ! ☺️
I am implementing a system in the virtual kernel/host service manager that is responsible for dedicating stack memory
Added a resb instruction that asks the kernel to give a specific thread n-bytes of heap space and use it as a thread-specific stack using push and pop instructions
My own language is terrorizing me to a point where I cannot distinguish c++ terminations from newasm crashes
build 32 rc
What's new or changed?
- Added the new
resbinstruction.
You use this instruction to ask the VM to dedicaten-number of bytes to a specific thread and use it as stack space.
.text
thread myThread -> {
resb 64 ; ask the system for 64 bytes of thread-safe stack space
push 429
push 'c'
push 873.45
}
Now, 64 bytes of stack space we got from the VM is just a part of the heap, but it is internally used as stack space since each thread has its own copy of the stack pointer because of the context-switching.
You can also use the stack instruction, the JIT compiler replaces standard push, pop and stack with internal thread-specialized versions. That means you can call procedures that accept arguments. This approach ensures memory thread-safety and speed.
You can still have access to the global stack from within the child procedures and encapsulated lambda procedures.
Fixed issues
- Fixed issue #36.
- Fixed issue #38.
- Fixed the
loopinstruction going into an infinite loop when the register is below 0 or 0.
thanks !!
build 32
What's new?
- Added instructions for error handling,
tryandcatch.
try
nop ; some code
catch ErrorLabel ; if there was an error, in code above, then jump to label
:ErrorLabel
; code that exits the app normally
; rax is gonna contain error code that was supposed to crash the application
Instruction try is used to begin a try-catch block. Essentially, try tells the program termination system that it should expect a catch instruction. When your app encounters an error, the program temporarily stops and checks if try was used, if it was it is going to jump to nearby catch instruction and then jump to an error-handling label.
.text
try
fetch nil ; set this ptr to nothing
mov this, 0 ; forcefully invoke an error
; <- since the error happened, code stops here and jumps to catch
nop ; more random code
catch error ; we provide a label
:come_back
; more code
ret 0 ; terminate your program
:error
mov tlr, "Error handled, error code: "
call std::ios::write
mov tlr, *rax ; catch ins stores an error code in rax
call std::ios::writeln
jmp come_back
You can use these in threads, procedures and lambda procedures. It is important to note you cannot have these nested at singular identation level, however you can have a separate try-catch block within a lambda and a thread.
So, you can't do:
try
try
try
catch what
catch smth
catch no
If you call a procedure that contains an error within try-catch block, and that procedure doesn't have its own catch, the procedure forcefully terminates and fallbacks onto the parent try-catch block.
So, you can do:
.text
proc ProcWithError
pddsfdssd ; purposefully try to use a non-existing dyn lib
mov tlr, "hi from ProcWithError"
sysenter "ios"
mov fdx, 1
syscall
halt 0
end
try
call ProcWithError
catch ErrorHandler
try
fetch nil
mov this, 3
nop
catch ErrorHandler
:Continue
zero rax
mov rax, 223 ; exit code
ret *rax ; returns from the whole program to the host OS or newasm shell
:ErrorHandler
mov tlr, "Error properly catched and handled, exit code: "
call std::ios::write
mov tlr, *rax
call std::ios::writeln
jmp Continue
Output will be:
Error properly catched and handled, exit code: 10
Or you can modify the ProcWithError procedure to just ignore the error with catch nil:
.text
proc ProcWithError
try
pddsfdssd ; purposefully try to use a non-existing dyn lib
catch nil ; just continue with execution
mov tlr, "hi from ProcWithError\n"
sysenter "ios"
mov fdx, 1
syscall
halt 0
end
And you get the output:
hi from ProcWithError
Error properly catched and handled, exit code: 14
Warnings
- Compiler is going to give you an error if you try to nest these on the same identation level.
- Compiler can optimize and remove empty try-catch blocks, such as:
try
catch smth
- You are going to get a runtime error if you do a
callcwithin a try-catch block if the address you are jumping to has a try-catch block.
- Optimized the following instructions:
heapdbfree
handwritten?
what's peephole
wdym handwritten
like not relying on generating LLVM IR or something to optimize
when it is removing or modifying a line the compiler is on, which means compiler's scope of view is just that line or two
bigger optimizations such as elimination of redundant functions etc require complete deepthrough analysis
of the whole program
no it is my bytecode
whoa
amen
Hi, uh, i am just new here and i dont knwo anything about C and Assembly. Please explain ts project (fyi i know C++)
Managed to add some primitive code analysis in the optimizer so it checks for unreachable code blocks
So it just cuts them from the binary
Looks fancy
Love it tbh
Any more recommendations for different patterns that modern compilers do ?
Because of Geode and Raylib :/
raylib is a C library
idk i just C++-ify Raylib
@twilit estuary has reached level 5. GG!
raylib-cpp?
but then i left raylib like some few weeks ago and now im into cli tools
you should check out my library maybe you'll like it better than raylib
and what do you make in CLI tools?
https://github.com/Orbier/orbit its a CMake Wrapper to simplify CMake
generator generating a generator generates build files to generate code
pretteh cool i'll check it out
Use it ples :].
well insetad of manually typing cmake -S . -B build -G Ninja -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang in the terminal, you just type orbit build --ninja --use-compiler=clang. Preety neat and simple. Also uses Unity btw with --unity flag
I have yet to make an installer for this :/.
how can I pass custom cmake variables to arguments
like -DSOME_CUSTOM_VARIABLE=42
U-u-unity?!
Yet to implement but thanks for suggsting (I Just directly use this shit)
bet
make your orbit project also use
orbit
bootstrap 💪 🚀
hmm....
i like risc and simple set of instructions that you can build complex things
section bss # initialize memory with zeros
entered reb 8 # 8 bytes
section data # data section
hello ascii "Hello, World!" # hello message
password ascii "mypass" # my password
match ascii "Unmatched!" # error message
section code # code section
entry start # entry start
start:
# read(0, entered, 6)
mov 0, r0
mov entered, r1
mov 6, r2
syscall 0
# compare strings
# compare_string(r1, r2)
mov password, r1
mov entered, r2
call compare_string
# if r6 == 1
cmp r6, 1
je matchedfunction # then jump matchedfunction
call unmatchedfunction # else call unmatchedfunction
compare_string: # args -> r1(string), r2(string) -> return value => r6
load r1, r10 # r10 = *r1
load r2, r11 # r11 = *r2
cmp r10, 0 # if r10 == '\0'
je .matched # then jump .matched
cmp r11, 0 # if r11 == '\0'
je .matched # then jump .matched
cmp r10, r11 # if r10 == r11 -> if "m" == "m"
je .matchednow # then jump .matchednow
jmp .unmatched # else jump .unmatched
.matchednow:
inc r1 # r1++ (r1 is pointer)
inc r2 # r2++ (r2 is pointer)
jmp compare_string # jump again compare_string (loop)
.matched: # matched
mov 1, r6 # r6 => return value -> r6 = 1 (true)
ret # return to start
.unmatched: # unmatched
mov 0, r6 # r6 => return value -> r6 = 0 (false)
ret # return to start
# r1 = 0
# write(1, hello, 14)
matchedfunction:
mov 0, r1
mov 1, r0
mov hello, r1
mov 14, r2
syscall 1
jmp exit
# r1 = 0
# write(1, match, 10)
unmatchedfunction:
mov 0, r1
mov 1, r0
mov match, r1
mov 10, r2
syscall 1
# exit(1)
exit:
mov 1, r0
syscall 60
heres my own cpu arch code
its so simple and you can build literally everything on this
this is the instruction set:
mov, add, sub, mul, div, and, or, xor, nop, not, shl, shr, jmp, je, jne, jl, jg, cmp, call, ret, push, pop, hlt, inc, dec, load, store, entry.
and this things is VM layer instructions
import, syscall, print
print is debugger for registers
like: print r1
out:
DEBUG: 0
tells the CPU where to start execution, like: start with this label (it’s a position)
ooo so it's customizable?!
the entry label is optional
wdym
nvm i thought it couldn't be changed on linux apparemtly it can
i have lot of examples with this cpu assembly, i do a webserver (raw sockets) for linux
oooo
thats kinda cool
section data
resp ascii "HTTP/1.1 200 OK" 13 10
ascii "Content-Type: text/plain; charset=utf-8" 13 10
ascii "Content-Length: 13" 13 10
ascii "Connection: close" 13 10 13 10
ascii "Hello, World!"
# len 112
sockaddr hword 2
hword 8080 !
# hword 36895 # BIG ENDIAN '8080'
# the ! operator is swaps bytes like 901F to 1F90
# or you can use bytes like this:
# byte 31
# byte 144
word 0
dword 0
section code
# socket(AF_INET=2, SOCK_STREAM=1, IPPROTO_TCP=6)
mov 2, r0
mov 1, r1
mov 6, r2
syscall 41
print r6
mov r6, r8 # server_fd
# bind(server_fd, &sockaddr, 16)
mov r8, r0
mov sockaddr, r1
mov 16, r2
syscall 49
print r6
# listen(server_fd, 16)
mov r8, r0
mov 16, r1
syscall 50
print r6
looper:
# accept(server_fd, NULL, NULL)
mov r8, r0
mov 0, r1
mov 0, r3
syscall 43
print r6
mov r6, r9 # client_fd
# write(client_fd, resp, 110)
mov r9, r0
mov resp, r1
mov 112, r2 # len from comment above
syscall 1
print r6 # bytes written
# close(client_fd)
mov r9, r0
syscall 3
print r6
jmp looper
exit:
mov 0, r0
syscall 60
here
yeah
very cool stuff