Day 24: My Assembly Internet Friend Comes to the Rescue
Instructions, registers, and assembler directives are always in UPPER CASE to remind you that assembly programming is a fraught endeavor. – A Quick Guide to Go’s Assembler
🌽 Mood: Ready to get lost in a corn maze.
🎵 Soundtrack: Happier Than Ever
📚 Reading Github Issues
Caught up on the 36 github issues opened in the last two days.
- One referenced bumping target test times by 100%. Relatable.
- One referenced the go fuzz (no hypen) minimizer and how it takes a long time to minimize very long inputs. Apparently the “removing every subset of bytes” part of the minimization can take awhile. Could be fun to dig into in the future.
📌 Updates on Older Contributions
On Aug 30, I wrote some code to add testable examples for all of the IP functions in the net package. According to the contribution guide: “Excluding very trivial changes, all contributions should be connected to an existing issue.” I thought testable examples might be classified as trivial, so I submitted my change and…🦗 🦗 🦗. Today I opened an issue and linked the submission to it in hopes that it will ping the reviewers 👀 .
Last week I submitted a change to improve the go fuzz (no hypen) minimizer. It wasn’t assigned any reviewers. I assumed this was because it was an off week for the go team. Today I decided to self-assign two people who I have seen in the go fuzz (no hyphen) area. Turns out it was a mistake with the configuration that it didn’t get a reviewer. Jay left some comments on the code that I hope to look at on Monday.
🤩 Assembly Help from an Internet Friend
Two days ago I asked for help in the #assembly channel in gopher slack and a nice internet stranger helped me. After doing what he suggested, I still had some open questions that I wrote in my post. They were…
- ❓ Why did I need to clear the DX register [before I used IDIVQ]? DX is the register where the remainder is stored. Why couldn’t IDIVQ just write over what is already in DX?
- ❓ Why did not clearing the register result in an error
panic: runtime error: integer divide by zero
? Neither the divisor or dividend were zero so why did I get this particular error?
Well, my thoughts must be pretty loud, because today MY INTERNET FRIEND ANSWERED THOSE QUESTIONS EVEN THOUGH I DIDN’T ASK HIM:
I thanked him, showed him my blog where I asked those exact questions, and he
came back with even more help. Thank you so much Damian!
🗳 Passing Variables by Register
Yesterday I ended stuck on getting my functions to pass arguments via registers without also getting a invalid memory address or nil pointer dereference error. Today I tried removing NOSPLIT since I knew it has something to do with stack frames and it worked!
💻 sender puts the integer 6 into two different registers and passes them to the function reciever.
💻 reciever takes the arguments and passes them to a go print function.
TEXT ·sender(SB),NOSPLIT,$0
MOVQ $6, SI
MOVQ $6, DX
CALL ·reciever(SB)
RET
TEXT ·reciever(SB),$0-16 // <--- No more NOSPLIT
PUSHQ BP
MOVQ SI, 0(SP)
MOVQ DX, 8(SP)
CALL ·print2Ints(SB)
POPQ BP
RET
NOSPLIT = 4 (For TEXT items.) Don’t insert the preamble to check if the stack must be split. The frame for the routine, plus anything it calls, must fit in the spare space remaining in the current stack segment. Used to protect routines such as the stack splitting code itself.
🧐 My guess for the reason for the error is that the frame for the routine, plus anything it called, did not fit into the spare space remaining in the current stack segment. I’m still not sure how to make it fit though.
🌎 Screw Passing Variables. Use Globals!
Globals! The last way to pass variables! Does it really count as a way to pass variables, though?
I struggled way too hard on this. It took me a bit to realize that I needed to
define DATA
and GLOBL
. I found examples in
go,
as always, to crib off of.
💻 printSixWithGlobals looks at a global variable where the integer 6 is stored and passes it to a go print function.
// DATA symbol+offset(SB)/width, value
DATA six+0x00(SB)/8, $6
// NOPTR - This data contains no pointers
// R0DATA - This data is read only
GLOBL six(SB),(NOPTR+RODATA),$8
TEXT ·printSixWithGlobals(SB),NOSPLIT,$0
PUSHQ BP
MOVQ six(SB), DX
MOVQ DX, 0(SP)
CALL ·printInt(SB)
POPQ BP
RET
➗ Odd Without DIV
My internet friend challenged me to rewrite my odd function, but not use DIV. Here’s what I came up with.
💻 oddWithNoDiv takes an integer and prints whether it is “even” or “odd”.
TEXT ·oddWithNoDiv(SB),NOSPLIT,$0
MOVQ val+0(FP), BX // BX = value to check
MOVQ $0, DX // DX = always 0
EVEN_LOOP:
CMPQ DX, BX // check if the value is 0
JGE PRINT_EVEN // if it is 0, then we know it is even
SUBQ $1, BX // else, subtract 1 from the value
JMP ODD_LOOP // try the odd loop
ODD_LOOP:
CMPQ DX, BX // check if the value is 0
JGE PRINT_ODD // if it is 0, then we know it is odd
SUBQ $1, BX // else, subtract 1 from the value
JMP EVEN_LOOP // try the even loop
PRINT_EVEN:
CALL ·printEven(SB)
JMP END
PRINT_ODD:
CALL ·printOdd(SB)
JMP END
END:
RET
🎥 Lecture 4: Assembly Language & Computer Architecture
With the last 30 minutes of my day (besides writing this blog), I watched the first half of this MIT lecture on “Assembly Language & Computer Architecture” that my internet friend recommended. The professor starts by saying programming assembly is “not as bad as you would think” and I whole heartedly agree! It’s been fun!
This lecture is definitely filling in some gaps.
Some learnings:
- In AT&T syntax the operand is second, in Intel syntax it is first.
- MOV is actually a copy. (I was wondering about this and was planning to test eventually).
- MOVC - a conditional move. This seems useful. I haven’t come across this instruction yet.
- When an integer is moved from a 32 bit register to a 64 bit register the extra bits are always zero extended. However when an integer is moved from any other smaller register to any other larger register it is overwritten and NOT zero extended.
- When you do an e (equal) or ne (not equal) condition, it checks the ZF (zero flag). This is because hardware typically compares two ints by doing subtraction. So if the result is 0 then it is equal and if it is not zero then they are not equal! 💥 🤯 🤩 Woah.
☀️ Long Weekend Time
On day one of looking into assembly I tried to read A Quick Guide to Go’s Assembler and it went so over my head. Today as I was skimming it I realized that I understand most of it now! Maybe not completely, but I have the building blocks to at least put things into context. I should re-read it from start to end. But that’s for another day.
Have a good weekend everyone!