8

I decided to take a crack at assembly the other day, and I've been playing around with really basic things like printing stuff from argv to stdout. I found this great list of linux syscall numbers with arguments and everything, and I'm curious why r10 is used for arguments before r8 and r9. I've found all kinds of weird conventions about what can be used what for what and when, like how loop counters go in rcx. Is there a particular reason why r10 was moved up? Was it more convenient?

I should probably also mention I'm interested in this out of curiosity, not because it's causing me problems.

Edit: I found this question which gets close, referencing the x64 ABI documentation on page 124, where it notes that user level applications use rdi, rsi, rdx, rcx, r8, r9. The kernel on the other hand uses r10 instead of rcx, and destroys rcx and r11. That might explain how r10 ended up there, but then why was it swapped in?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Monchoman45
  • 517
  • 1
  • 7
  • 17
  • Because [Why do x86-64 Linux system calls modify RCX, and what does the value mean?](//stackoverflow.com/q/47983371). Just replacing RCX with R10 allows a single `mov r10,rcx` ; `syscall` in libc wrapper functions. [Why Assembly x86\_64 syscall parameters are not in alphabetical order like i386](//stackoverflow.com/q/47676657) – Peter Cordes Nov 17 '19 at 19:28

2 Answers2

9

RCX, along with R11, is used by the syscall instruction, being immediately destroyed by it. Thus these registers are not only not saved after syscall, but they can't even be used for parameter passing. Thus R10 was chosen to replace unusable RCX to pass fourth parameter.

See also this answer for a bit more information on how syscall uses these registers.

Reference: Intel's Instruction Set Reference, look for SYSCALL.

Community
  • 1
  • 1
Ruslan
  • 18,162
  • 8
  • 67
  • 136
2

see x86-64.orgs abi documentation page 124

  1. User-level applications use as integer registers for passing the sequence %rdi, %rsi, %rdx, %rcx, %r8 and %r9. The kernel interface uses %rdi, %rsi, %rdx, %r10, %r8 and %r9.

  2. A system-call is done via the syscall instruction. The kernel destroys registers %rcx and %r11.

This is saying that when you use the syscall instruction the kernel destroys %rcx so you need to use %r10 instead.


Also the comment from @technosaurus explains that the kernel is using %rcx to store the entry point in case of an interrupt during a syscall.

James
  • 1,009
  • 10
  • 11
  • Is this referring to syscalls? With `mmap` for example, you pass flags in `r10`, and flags are not a static chain pointer. – Monchoman45 Jan 24 '14 at 03:13
  • I'm not sure.. i'm confused now, i think (i thought) it was used behind the scenes to calculate the addresses of the arguments on the stack, on page 123 _Linux Conventions_ it says "The Linux AMD64 kernel uses internally the same calling conventions as user-level applications (see section 3.2.3 for details)" - _(the beginning of the section i pointed you to??)_ – James Jan 24 '14 at 03:35
  • I found [this question](http://stackoverflow.com/a/2538212/849185) which gets close, referencing the same document on page 124, where it notes that user level applications use `rdi, rsi, rdx, rcx, r8, r9`. The kernel on the other hand uses `r10` instead of `rcx`, and destroys `rcx` and `r11`. That might explain how `r10` ended up there, but then why was it swapped in? – Monchoman45 Jan 24 '14 at 04:47
  • 124 - not that it's swapped for the destroyed `rcx`, but rather that the kernel does not accept an argument in `rcx`, the fourth argument is stored in `r10` instead, and when the syscall returns `rcx` is destroyed. (at least as I understand it) – Monchoman45 Jan 24 '14 at 06:33
  • According to ftp://ftp.csc.fi/pub/Linux/kernel/v2.4/patch-html/patch-2.4.20/linux-2.4.20_arch_x86_64_kernel_entry.S.html it looks like rcx is used by the kernel to store the entry point in case of an interrupt, but for convenience r10 is copied to rcx on return, so a simple mov from rcx to r10 before the syscall should suffice. – technosaurus Aug 07 '15 at 07:04
  • @technosaurus ahh thanks for the information, i think i'd completely missed the point and misunderstood everything, i should probably edit my answer to at least answer the question, seems OP was right on the money with referencing page 124 and I don't know what I was on about. – James Aug 07 '15 at 17:30
  • I never did track down exactly why rcx was used to save the entry point instead of r10... Maybe it's the last one guaranteed not to be clobbered by interrupts... Pure speculation – technosaurus Aug 07 '15 at 21:40
  • @technosaurus The `syscall` instruction *itself* destroys RCX (and R11). AMD designed it that way. GCC devs still chose RCX for the user-space calling convention to save code size (avoid REX prefixes). [Why do x86-64 Linux system calls modify RCX, and what does the value mean?](https://stackoverflow.com/q/47983371) – Peter Cordes Oct 16 '20 at 04:24
  • [What's the best way to remember the x86-64 System V arg register order?](https://stackoverflow.com/q/63891991) has some discussion of that design decision. – Peter Cordes Oct 16 '20 at 04:29