0

I have the following disassembly of a main function in which a user input is stored using scanf function (at address 0x0000089c). Due to the comparison that is made, I suppose that the user input is stored into the rsp register but I cannot figure out why, as rsp doesn't seem to be pushed on the stack (at least, not near the call to the scanf function). Here is the disassembly:

0x00000850 sub rsp, 0x18
0x00000854 mov rax, qword fs:[0x28]
0x0000085d mov qword [canary], rax
0x00000862 xor eax, eax
0x00000864 call fcn.00000a3c
0x00000869 lea rsi, str.Insert_input:
0x00000870 mov edi, 1
0x00000875 xor eax, eax
0x00000877 mov dword [rsp], 0
0x0000087e mov dword [var_4h], 0
0x00000886 call sym.imp.__printf_chk
0x0000088b lea rdx, [var_4h]
0x00000890 lea rdi, str.u__u  ; "%u %u" ;const char *format
0x00000897 xor eax, eax
0x00000899 mov rsi, rsp
0x0000089c call sym.imp.__isoc99_scanf ; int scanf(const char *format)
0x000008a1 mov eax, dword [rsp]
0x000008a4 cmp eax, 0x1336
0x000008a9 jg 0x867
  • The parameters of `scanf` (except the format string that is) are not passed in registers, but rather on the stack. Though, technically, the way that parameters are passed to variadic functions is platform-dependent, but you can read more about that here: https://stackoverflow.com/questions/23104628/technically-how-do-variadic-functions-work-how-does-printf-work – Ætérnal Jun 03 '22 at 16:41
  • 1
    @Ætérnal this is wrong, on x64, the first 6 arguments are passed in following registers in that order: rdi, rsi, rdx, rcx, r8, r9. Only if there are 7 or more arguments, arguments 7 to N are pushed on the stack. Also I don't know what makes you think the format string pointer is passed on the stack her, it is passed in rdi. – Jabberwocky Jun 03 '22 at 16:51
  • @Jabberwocky Let's suppose that the architecture is x86 so the parameters are passed on the stack. Moreover, rsp is used as the stack frame pointer and so it contains a poniter to the topmost element on the stack. So why does, in this case, rsp contain the user input as it isn't the topmost element on the stack? –  Jun 03 '22 at 16:54
  • @Giovanna the architecture in your sample is x64, there are no `rxx` registers (like rdx, rdi, rsp etc.) on x86. – Jabberwocky Jun 03 '22 at 16:55
  • @Jabberwocky yes, you're right. So why does rsp, and not rdi, contain the user input? –  Jun 03 '22 at 16:57
  • 1
    @Giovanna it doesn't. `rsp` _points_ to the variable that will contain the user input. – Jabberwocky Jun 03 '22 at 17:00
  • @Jabberwocky is this a general rule when using scanf? –  Jun 03 '22 at 17:02
  • 1
    It has nothing to do with `scanf`. Here for whatever reason `rsp` points to some (probably local) variable where the user input should go, IOW that variable is on the stack. After `mov rsi, rsp`, `rsi`points to that variable, and as explained before `rsi` is the second argument for `scanf` and the second argument of `scanf` is the address where the user input shopuld be stored. You need to study all this calling convention stuff and assembly stuff, I'm sure it's explained in your learning material. – Jabberwocky Jun 03 '22 at 17:08
  • @Jabberwocky I think that I have understood what you're saying. I thought that scanf had just an argument (the user input) and that that parameter should have been saved in rdi, that's why I didn't figure out why rsp is pointing to the variable with the user input... Thanks! –  Jun 03 '22 at 17:15

1 Answers1

2

On x86_64, parameters are passed in registers, so your call to scanf has 3 parameters stored in 3 registers:

  • rdi pointer to the string "%u %u", the format to parse (two unsigned integers)
  • rsi should be a unsigned *, pointer to where to put the first parsed integer
  • rdx pointer to where to put the second parsed integer.

If you look just before the call, rsi is set to rsp (the stack pointer) while rdx is set to point at the global variable var_4h (an extern symbol not defined here).

The stack is used to hold local variables, and in this case rsp points at a block 0x18 "free" bytes (allocated in the first instruction in your block), which is enough space for 6 integers. The one at offset 0 from rsp is what rsi points to, and it is the value read by the mov instruction immediately after the call.

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
  • Thanks, you've been very clear! So, is it correct to say that rsp (at offset 0) and rsi point to the same block after the scanf call? –  Jun 03 '22 at 19:35
  • Actually, only before the call -- scanf might modify esi internally (it is not caller save). – Chris Dodd Jun 03 '22 at 19:41
  • So, before the scanf call, rsp (at offset 0) and rsi point both to the bock which will contain the user input, did I understand? –  Jun 03 '22 at 19:43
  • 1
    rsp and rsi both point at the block, which is at offset 0 from either of them – Chris Dodd Jun 03 '22 at 19:45
  • After the call to scanf, the integer at offset 0 from rsp will contain the user input, right? –  Jun 03 '22 at 20:06
  • 2
    The variable meant to capture the output of the `%u` is on the stack, that is the only relation with `rsp`. Otherwise `rsp` is communicating to `scanf` where the stack is in case it wants some stack space to use for itself. Here, with 3 parameters, `rsp` is not involved in any parameter passing for this call, except sharing where the current stack pointer is, and hence identifying where free stack memory is. – Erik Eidt Jun 03 '22 at 23:41