From 218d1c9d6c8c1ec7928dff8979b5fc9be2ee07a7 Mon Sep 17 00:00:00 2001 From: shockrah Date: Tue, 19 Aug 2025 23:00:16 -0700 Subject: [PATCH] Updating lecctures and readme for relevancy --- 337/lec/lec2.md | 82 +++++++++++++++++++++++++++++++++-------- 337/lec/lec3.md | 19 ++++------ 370/homework/huffman.py | 2 +- readme.md | 9 +++++ 4 files changed, 85 insertions(+), 27 deletions(-) diff --git a/337/lec/lec2.md b/337/lec/lec2.md index 461c3d8..0d3ea83 100644 --- a/337/lec/lec2.md +++ b/337/lec/lec2.md @@ -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. 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 To find the Negation of any bit-string: +i.e. `3 * -1=> -3` + 1. Flip all bits in the bit-string 2. Add 1 to the bitstring +The case for 3: + +``` +start off: 0011 => 3 + +flip bits: 1100 => -2 + +add one: 1101 => -3 + +``` + ### Signedness > Why? 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. -If we needed negative represenation 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. -If it were 1 we would have a _signed_ number. +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 representation however, we have to sacrifice some of our range. +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`. +Our negative range is then `-8 -> -1` which in binary is `0b1000 -> 0b1111` + ## Intro to hex > 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. @@ -41,24 +88,29 @@ More pedantically our new hex range is 0x00 to 0xff. > Binary mapped -It happens that 1 nibble makes up 0x00 to 0xFF. -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. -Then just move on to using hex(like immediately after these lessons). -Even the most obfuscated binary files out there don't resort to architectural obfuscation; until they do. +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 eventually it should be second nature. +Then just move on to using hex(like immediately after these lessons), because writing actual binary is actually awful. + +> 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 -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 -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... diff --git a/337/lec/lec3.md b/337/lec/lec3.md index d0305b3..684872f 100644 --- a/337/lec/lec3.md +++ b/337/lec/lec3.md @@ -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_. -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. +To make this into a `-3` we: -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. -The actual term for this is just __negate__; the other way around is essentially cannon fodder. +It matters because certain types operations _just suck_ on pretty much every general use platform. ->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. diff --git a/370/homework/huffman.py b/370/homework/huffman.py index 7b5c95a..a724b0c 100644 --- a/370/homework/huffman.py +++ b/370/homework/huffman.py @@ -88,7 +88,7 @@ if __name__ == "__main__": # build up our heap to display info from heap = encode(frequencies)[0] - #print(heap) + print(heap) # decode the binary decode(heap, binary) diff --git a/readme.md b/readme.md index 47636cd..9f2ab2b 100644 --- a/readme.md +++ b/readme.md @@ -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 To some degree these notes are personal so there are a few mistakes that I just can't be bothered dealing with.