HN user

ashdnazg

177 karma

https://ashdnazg.github.io

Posts5
Comments59
View on HN

I worked on a transpiler from Nand2tetris assembly to WebAssembly, and had some really annoying memory corruption bug that I just couldn't solve.

That is, until I checked the program I used for testing (which I didn't write), and found the following code:

  dealloc(this)
  return this->field
With the original allocator, this worked fine, since the deallocation didn't touch the memory.

My allocator, however, overwrote the field during the deallocation with bookkeeping stuff, which meant the returned value was not what the programmer intended and after a short while the program crashed.

Unlike TFA, I had the luxury of just fixing the test program.

Stop Killing Games 2 months ago

Kind of depends on the definition of no one.

If the company puts an artificial proof of work demanding a rack of the latest data center GPUs, that should be illegal.

If the binary has the same hardware requirements that the company used when the service was up, I see it as totally fair.

Stop Killing Games 2 months ago

The key is communication. If the company says the binary has a certain min. requirement, then the vast majority of people will accept that.

Of course there'll be idiots, but I doubt you'll see a stronger backlash than to a company shutting down the servers without any solution, like they can do now.

Stop Killing Games 2 months ago

But the server binary doesn't start unless you have 190GiB of RAM and 38 available CPUs.

As far as I understand that situation is accepted by the initiative. The requirement is not that it works on any specific hardware or software stack, just that it can theoretically work.

a binary that can be used to create cheats against the next version of the product

Anti-cheat solutions aren't required to be released, and if there are bugs in the server, they might even be found and patched by the community.

The real question is how many other things it's missing.

Reading the process in TFA, it's very much dependent on the comprehensiveness of the testing framework. And apparently, the tests never built a lobby in the bottom left corner...

Anything else it didn't try, is probably also not documented and not implemented.

With the growing use of AI in reverse engineering, we might need to shift our goals to more strongly verifiable ones, such as matching decompilation.

Fluent means different things to different people (and in different languages!).

As I understand it, B2 means one has a solid, functional proficiency in the language. They conversate/listen/read/write in diverse situations, without needing to switch to a different language or to prepare in advance.

They're very likely, however, to make mistakes, say things in non-idiomatic ways etc. although this is expected to be minor enough to not affect the ability to understand them.

In order to get to C1 and above, one needs a deeper understanding of the language - phrases, idioms, connotations, registers, etc. and a broader set of situations they can handle, e.g., a philosophical discussion. An of course, errors are expected to be rarer.

So, literally speaking, B2 is rather fluent, since the language is "flowing" out of them and they're not stopping to think every other word (which is, as far as I understand, a common interpretation of flüssig in German).

But as "fluent" speakers should know, words come with expectations beyond the literal meaning :P

I'm back to searching for numbers that are palindromes both in decimal and in binary. [0]

I had an insight the other day, that as I fix the n least (and most, it's a palindrome!) significant decimal digits, I also fix the remainder from division in 5^n. Let's call it R. Since I also fix by that point a bunch of least (and most) significant bits, I can subtract how much they contribute mod 5^n from R, to get the remainder from division in 5^n of the still unknown bit. The thing is, maybe it's not possible to get this specific remainder with the unknown bits, because they're too few.

So, I can prepare in advance a table of size 5^n (for one or more ns) which tells me how many bits from the middle of the palindrome I need, to get a remainder of <index mod 5^n>.

Then when I get to the aforementioned situation, all I need to do is to compare the number in the table to number of unknown bits. If the number in the table is bigger, I can prune the entire subtree.

From a little bit of testing, this seems to work, and it seems to complement my current lookup tables and not prune the same branches. It won't make a huge difference, but every little bit helps.

The important thing, though, is that I'm just happy there are still algorithmic improvements! For a long while I've been only doing engineering improvements such as more efficient tables and porting to CUDA, but since the problem is exponential, real breakthroughs have to come from a better algorithm, and I almost gave up on finding one.

[0] https://ashdnazg.github.io/articles/22/Finding-Really-Big-Pa...

I did some manual golfing with nand2tetris assembly and developed similar hacks to the max() implementation, where one appropriates an arbitrary, conveniently placed, memory address.

After reading the article, though, I feel like I definitely need a superoptimiser, to see what could be improved :)

Poor Man's Polaroid 5 months ago

If you're using mobile, there's an "English" button in the menu.

Note to website owner - it could be nice to have a permalink to the English version.

for this game you can throw the usual tools away...

The reason is that Starflight was written in Forth

I recently reverse-engineered another game from the 80's, and had a similar issue because it was written with Turbo Pascal.

The different tools didn't like quirks such as data stored inline between the instructions or every library function having a different calling convention.

Turns out the simplest way to handle this was to write my own decompiler, since Turbo Pascal 3 didn't do any optimisations.

In academia, seeing your research being published by someone else sucks, but the consolation prize is that you know you had the right instincts choosing what to research.

Advent of Code 2025 8 months ago

My wife did one of the years in Matlab. Some of the problems translate very nicely into vectors and matrices.

The bare basics are working with a hex editor and understanding data types - ints, floats, null-terminated strings, length-prefixed strings etc.

I'd recommend taking a well documented binary file format (Doom WAD file?), go over the documentation, and see that you manage to see the individual values in the hex editor.

Now, after you have a feel for how things might look in hex, look at your own file. Start by saving an empty project from your program and identifying the header, maybe it's compressed?

If it's not, change a tiny thing in the program and save again, compare the files to see what changed. Or alternatively change the file a tiny bit and load it.

Write a parser and add things as you learn more. If the file isn't intentionally obfuscated, it should probably be just a matter of persevering until you can parse the entire file.

Porting my binary & decimal palindromes[0] finding code[1] to CUDA, with which I had no experience before starting this project.

It's already working, and slightly faster than the CPU version, but that's far from an acceptable result. The occupancy (which is a term I first learned this week) is currently at a disappointing 50%, so there's a clear target for optimisation.

Once I'm satisfied with how the code runs on my modest GPU at home, the plan is to use some online GPU renting service to make it go brrrrrrrrrr and see how many new elements I can find in the series.

[0] https://oeis.org/A007632

[1] https://github.com/ashdnazg/palindromes

O(n^2) isn't required. One could do an in-place merge-sort, which is also always worst case, but with O(n*log(n)).

I suspect everyone turns to Bubblesort since the inputs are small enough that it doesn't matter (evident by the fact that it should fit within microseconds).

You could copy the instruction to a 16 byte sized buffer and hash the one/two int64s. Looking at the code sample in the article, there wasn't a single instruction longer than 5 characters, and I suspect that in general instructions with short names are more common than those with long names.

This last fact might actually support the current model, as it grows linearly-ish in the size of the instruction, instead of being constant like hash.

Thank you!

It's similar with Turbo Pascal 3.0, but there's only one segment since it's a good old COM file. The compiler just copies its own first ~10000 bytes, comprising the standard library, and splices the compiled result to the end.

I can see how this makes transcompilation relatively straightforward, although the real mode 16-bit code is a bit unpleasant with all the segment stuff going on, so you might as well just decompile :D. It's very possible that similar instructions will be emitted in 3.0 and 4.0 for the same source input.

My program also has the stack checking calls everywhere before calling functions. I think that people using Pascal weren't worried about performance that much to begin with, so they didn't bother disabling it.

I'm writing a decompiler for Turbo Pascal 3.0, to reverse engineer an educational game from the 80s.

Since TP 3.0 does no optimisations, and looking at the progress so far (~25% decompiled), it seems like matching decompilation should be achievable.

If/when I get to 100%, I hope to make the process of annotating the result (Func13_var_2_2 is hardly an informative variable name) into a community project.

That's a good point, the matter of timing different fleets from different sources to arrive at the same time is definitely an operational challenge.

I think it's a bit difficult to describe a game as purely strategic/operational/tactical.

Games can contain strategic/operational/tactical elements or choices, and I would say that a game where the vast majority of choices are operational can be called an "operations game".

When I played Konquest/Galcon, I felt that the biggest challenge was figuring the correct timing and order of expansion, which to me feels like strategy. It's very possible that AIs would disagree with me.

I also thought about this type of game!

I have more experience with the discrete version - e.g., Konquest[0].

I think it's not very operational, as getting your ships to battle is as simple as saying go from A to B. Your operational choices boil down to whether you want to pass through planet C, to trade time for flexibility.

While it has perfect information over your own ships, I think the core idea can be easily adapted to have separate players controlling separate planets, with delayed communication, both for people playing this game and for an AI competition.

[0] https://apps.kde.org/en-gb/konquest/