Re: Question about AMD64 ABI
- Reply: Daniel Cervus : "Re: Question about AMD64 ABI"
- In reply to: Daniel Cervus : "Re: Question about AMD64 ABI"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 13 Nov 2022 09:50:10 UTC
On Sun, Nov 13, 2022 at 4:07 AM Daniel Cervus <DanieltheDeer@outlook.com> wrote: > Hi Paul, > > You mean I need to ensure higher bits are zeros (including signed int, > short, char...) when passing the parameters? Okay, I get it. > That's not what I said. I said: "32-bit operands generate a 32-bit result, zero-extended to a 64-bit result in the destination general-purpose register." I also said: "16 and 8 bit operands don't have this "built-in" so you would indeed need to ensure the higher bits are cleared." So what does this mean? Let's take the following C function prototype as well as its implementation .. something I just pulled out of thin air and is useless, but is only for demonstration purposes: ; rdi ; long long iAmGoingToDoStuff(long long value) iAmGoingToDoStuff: inc rdi mov rax, rdi ret Now let's take two separate asm snippets...one that WILL work as expected and another that WON'T work as expected: The working example is the easiest. Even though the prototype declares it accepts a long long, we only have to explicitly set edi as it's a 32 bit operand that automatically gets zero extended to 64 bits. workingExample: xor edi, edi ; Pass 0, all bits in rdi are 0 due to abi rules call iAmGoingToDoStuff ret With the nonworking example I've tried to provide a scenario with the value stored in edi was previously set by an outside force. That's the first `mov'. The second `mov' in this example only sets the lower 4 bits of edi, leaving the rest of the register alone. If the intent was to set the register to 0, then this is obviously a problem and you would have to ensure to clear the proper bits. nonWorkingExample: mov edi, 0xCF0A ; Set edi to a random value mov dl, 0 call iAmGoingToDoStuff ret My advice regarding manipulating 16 bits or smaller registers is ... don't unless you absolutely have to. If you know what EFLAGS stalls are and know some 16 computations you're doing won't stall on it, then it's not a problem. It's best however to just avoid them altogether. (Exceptions apply but are far as few between). By the way, is there any good resources that I can learn 64-bit FB (or > *nix) assembly programming from? > > This answer might seem clique but I swear it's not the intention. The best reference for instructions, associated operands, rules regarding zero extending of 32-bit registers, etc., is right in the manual: https://cdrdv2.intel.com/v1/dl/getContent/671110 The above naturally doesn't "teach" assembly, but it will be your "goto" for just about everything. I've been programming in assembly for well over 2 decades, damn nearing 3 decades now, and it's STILL the Holy Bible of how a CPU ticks ( no pun intended). With that said, each assembler has their own syntax when it comes down to translating its version of assembly into machine code. I certainly advocate for nasm as it's my goto but others might find the syntax of fasm, for example, more to their liking. It's up to you to find an assembler that's to your liking and read it's manual through and through. > Regards, > Daniel > > > ~Paul > 在 2022年11月13日,下午4:52,Paul Procacci <pprocacci@gmail.com> 写道: > > > > > On Sat, Nov 12, 2022 at 10:31 PM Daniel Cervus <DanieltheDeer@outlook.com> > wrote: > >> Hi everyone, >> >> I’m trying to do assembly programming on FB in 64-bit mode. I have a >> question, 64-bit mode requires parameters to be passed on 64-bit registers. >> But when a parameter is 32-bit or smaller, do I need to sign-extend (or >> zero-extend) them to 64-bit? The System V ABI specifications only says "The >> size of each argument gets rounded up to eightbytes." It’s somewhat >> ambiguous. How to round up 'float', when they are passed on stack? >> >> Thanks, >> Daniel > > > (Didn't Reply all) > > Hi Daniel, > > There are a handful of operations that operate on 32bit registers that > automatically clear the high bits for you. > > 32-bit operands generate a 32-bit result, zero-extended to a 64-bit result > in the destination general-purpose register. > 16 and 8 bit operands don't have this "built-in" so you would indeed need > to ensure the higher bits are cleared. > > mov dword edi, 1 is effectively setting rdi to the value of > 0x0000000000000001 > > As for sign extending the values, the answer is `no'.....under most > circumstances. If you are sticking to widths of 32 and 64 bits then you > are fine. > The moment you mess with 16bits or smaller, then yes, you need to ensure > no garbage lives in your higher bits because the cpu doesn't clear this for > you. > > "The size of each argument gets rounded up to eight bytes." > > The size of ALL arguments passed to the callee via general purpose > registers is 8 bytes "regardless of what a function def says". It's HOW > the callee operates upon the register arguments that matters. > > As for passing arguments on the stack ... you shouldn't have to. Not > only are there the GPR's rdi, rsi, rdx, rcx, r8, r9, r10 at your disposal > for int/scalar types there are also xmm0-xmm7 for your floats. > > Thanks, > ~Paul > > -- > __________________ > > :(){ :|:& };: > > -- __________________ :(){ :|:& };: