Updating lecctures and readme for relevancy

This commit is contained in:
shockrah 2025-08-19 23:00:16 -07:00
parent 04ec3696b8
commit 218d1c9d6c
4 changed files with 85 additions and 27 deletions

View File

@ -10,29 +10,76 @@ Most typically we deal with binary(when we do) in nibbles or 4 _bit_ chunks whic
Ex:`0101 1100` is a basic random byte. Ex:`0101 1100` is a basic random byte.
For most sane solutions this is essentially the only way we __ever__ deal with binary. For most sane solutions this is essentially the only way we __ever__ deal with binary.
> Why can't we (((save bits))) and not use nibbles?
In truth you can totally do that; but not really.
To explain let's look at some higher level C/C++ code; say you had this structure:
```
struct Point {
int x; // specifying width for clarity sake
int y;
unsigned int valid : 1;
};
```
On a typical x86 system(and many x64 systems) with no compile time optimizations this structure might look like:
```
32(int x) + 32(int y) + 1(unsigned int valid) + 7(bits of padding)
```
Why? Because while we can always calculate the address of a particular byte's address in memory we cant' or rather don't even try to do the same for bits.
The reason is simple: a 32bit CPU can calulate any number inclusively between `0` and `0xffffffff` or `4294967295`. That means we have an entropy pool large enough to have 1 number per byte but not enough to include the bits as well.
If we use that `valid` _bit-field_ in our code later like
```
if(point_ref->valid) {
/* do stuff */
}
```
The machine code instructions generated will really just check if that byte(which contains the bit we care about) is a non-zero value.
If the bit is set we have (for example) `0b0000 0001` thus a _true_ value.
## Two's Complement - aka Negate ## Two's Complement - aka Negate
To find the Negation of any bit-string: To find the Negation of any bit-string:
i.e. `3 * -1=> -3`
1. Flip all bits in the bit-string 1. Flip all bits in the bit-string
2. Add 1 to the bitstring 2. Add 1 to the bitstring
The case for 3:
```
start off: 0011 => 3
flip bits: 1100 => -2
add one: 1101 => -3
```
### Signedness ### Signedness
> Why? > Why?
Because this matters for dealing with `signed` and `unsigned` values. _No it doesn't mean positive and negative numbers._ Because this matters for dealing with `signed` and `unsigned` values. _No it doesn't mean positive and negative numbers._
Say we have 4 bytes to mess with. This means we have a range of 0000 to 1111. If we wanted pureley positive numbers in this range we could have 0000 to 1111... or 0 to 15. Say we have 4 bytes to mess with. This means we have a range of 0000 to 1111. If we wanted purely positive numbers in this range we could have 0000 to 1111... or 0 to 15.
If we needed negative represenation however, we have to sacrifice some of our range. If we needed negative representation however, we have to sacrifice some of our range.
Our new unsigned range is 0-7. We say it's unsigned because the first bit here is 0. Our new unsigned range is then `0-7` _or in binary_: `0000 - 0111`. We say unsigned for this range because the largest number we can represent without setting the first bit is `0111` => `7`.
If it were 1 we would have a _signed_ number. Our negative range is then `-8 -> -1` which in binary is `0b1000 -> 0b1111`
## Intro to hex ## Intro to hex
> Hex Notation 0x... > Hex Notation 0x...
x86 assemblersi(masm) will typically accept `...h` x86 assemblersi(masm) will typically accept `...h` as a postfix notation.
More convinient than binary for obvious reasons; namely it doesn't look like spaghetti on the screen. More convinient than binary for obvious reasons; namely it doesn't look like spaghetti on the screen.
@ -41,24 +88,29 @@ More pedantically our new hex range is 0x00 to 0xff.
> Binary mapped > Binary mapped
It happens that 1 nibble makes up 0x00 to 0xFF. It happens that 1 nibble makes up 0x0 to 0xF.
So for now just get used to converting {0000-1111} to one of it's respective values in hex and evetually it should be second nature. So for now just get used to converting {0000-1111} to one of it's respective values in hex and eventually it should be second nature.
Then just move on to using hex(like immediately after these lessons). Then just move on to using hex(like immediately after these lessons), because writing actual binary is actually awful.
Even the most obfuscated binary files out there don't resort to architectural obfuscation; until they do.
> Dude trust me hex is way better to read than decimal
It may seem convenient at first but after a while you'll realized that hex has really easy to understand uses and makes this super clear + concise, especially when dealing with bit masks and bitsets.
> Ascii in Hex Dumps > Ascii in Hex Dumps
Kind of a side note but most ascii text is from 0x21 to 0x66ish[citation needed] Kind of a side note but most ascii text values range from 0x21 to 0x66 so if you're looking for text in a binary look for groupings of that value.
## 32 v 64 bit ## 32 v 64 bit
For those with a 32 bit background know that these notes deal with 64-bit architecutres mostly. So some quick terminology which might randomly throw you off anyway. In case you come from an x86_64 ish background know that in MIPS terminology changes a bit(bun intended).
> double-byte/ half-word > x86 byte = mips byte
The latter is dumb but soemtimes used so wtever. > x86 word = mips half word
> word = 4 bytes > x86 dword = mips word
Etc onward with doubles, quads... > x86/64 qword = mips mips dword
So just keep those translations in mind...

View File

@ -1,22 +1,19 @@
# lec3 # Lecture 3
## One's & Two's Complement ## One's & Two's Complement (in depth(or something))
_Previous lecture went over signedness of numbers so this section won't as much_. In order to change recall from last lecture that we wanted to represent `3` with a single nibble like so `0b0011`.
First we'll deal with flipping bits: this is where you may hear the term _1's complement_. To make this into a `-3` we:
While not very useful on it's own for most purposes it does help get closer to creating a seperation between _positive_ and _negative_ numbers.
The only other step after flipping all the bits is just adding 1. 1. Flipped all the bits : `value xor 0xff..`
`1001 1110` becomes `0110 0010`. 2. Added 1 to the result of step 1
> shouldn't that last 2 bits be 01? > Ok, but like, why do I care? we're just multiplying things by -1 how does that matter at all?
Close, the reason why we have `b10` is because if we: `b01 + b1` the `1` will carry over to the next bit. It matters because certain types operations _just suck_ on pretty much every general use platform.
The actual term for this is just __negate__; the other way around is essentially cannon fodder.
>Ok, but what does that look like _assembly_ the thing I came here to learn.
Most assemblers accept something like `neg targetValue` however you can also use an _exclusive or_[`xor targetValue, 0xFF`]. Keep in mind that the immediate value should be sign-extended to reflect the proper targetValue size. Most assemblers accept something like `neg targetValue` however you can also use an _exclusive or_[`xor targetValue, 0xFF`]. Keep in mind that the immediate value should be sign-extended to reflect the proper targetValue size.

View File

@ -88,7 +88,7 @@ if __name__ == "__main__":
# build up our heap to display info from # build up our heap to display info from
heap = encode(frequencies)[0] heap = encode(frequencies)[0]
#print(heap) print(heap)
# decode the binary # decode the binary
decode(heap, binary) decode(heap, binary)

View File

@ -1,3 +1,12 @@
# Holy Moly
These notes are ancient but I like keeping them around because it reminds of
my college days when I didn't really know much :3
Not sure who will find value from these but here's some random tidbits of knowledge
# Everyone else # Everyone else
To some degree these notes are personal so there are a few mistakes that I just can't be bothered dealing with. To some degree these notes are personal so there are a few mistakes that I just can't be bothered dealing with.