0

According to the standard calling convention the arguments in argv are stored in the register rsi.

Assuming, my argc is 2 and my command line is something like:

./program a

I want to compare if something is equal to "a". I have the following code:

mov r12, rsi
mov r13, 0
mov r14, qword[r12+r13*8]
cmp r14, "a"
je Success

; Code here that displays error

Success:
; etc.

So, I am not sure what I am doing wrong, but it doesn't jump to success, but it should right?

I would appreciate any help.

Vroryn
  • 125
  • 6
  • 1
    @David, r14 is loaded with argv[0], so it’s not going to crash. But it should set r13 to 1 to load argv[1]. – prl Oct 13 '18 at 04:14
  • 2
    Vroryn, you need to compare each byte that r14 points to with each byte of the string you are comparing to. – prl Oct 13 '18 at 04:16
  • @prl Setting r13 to 1 solved this. Thank you! – Vroryn Oct 13 '18 at 04:54
  • @prl I would be grateful if you could explain, why the argument is loaded in arv[1], shouldn't the first argument be loaded in arg[0]? – Vroryn Oct 13 '18 at 05:00
  • 2
    C11 standard: "If the value of argc is greater than zero, the string pointed to by argv[0] represents the program name". – rkhb Oct 13 '18 at 05:41
  • FWIW, there is no "standard" calling convention. I assume you mean the System V 64 bit ABI, which is used by a number of OSes? – Rudy Velthuis Oct 13 '18 at 16:32

1 Answers1

1
  • You're overcomplicating this with more instructions than necessary
  • a will be argv[1], but you're loading argv[0] (by convention the program name, but could be a NULL pointer or arbitrary string if your program is invoked with execve() from something other than a normal shell).
  • you're comparing "a" with the pointer value, not with the pointed-to string data.

i.e. the C version of what you wrote is

if( (intptr_t)argv[0] == "a" ){
    success:
}

For an assemble-time-constant index, you should just use a displacement instead of an index register. You can write it in a way that looks nice for humans using an assemble-time expression like 1 * 8 or 0 * 8.

global main
main:
    cmp   edi, 2
    jb    too_few_args        ; if(argc<2) avoid segfaults in both of the next 2 insns

    mov   rdx, [rsi + 8*1]    ; r14 = argv[1]
    cmp   byte [rdx], "a"     ; argv[1][0] == 'a'
    je    success

      ...

success:
     xor  eax,eax
     ret                   ; return 0

r14 is a call-preserved register in the x86-64 System V ABI, so if your main returns instead of call exit, you should leave R14 with the same value it had on entry. What registers are preserved through a linux x86-64 function call

RDX is call-clobbered, so it's a good choice for a scratch register.

It also saves a byte of code-size to use RDX or some other scratch register that doesn't need a REX prefix instead of R8..15. The qword mov will always need a REX prefix, but the byte cmp won't.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847