Process Command Line in Linux 64 Bit

Process command line in Linux 64 bit

You are loading the correct address into %rcx.

int 0x80 then invokes the 32-bit syscall interface. That truncates the address to 32 bits, which makes it incorrect. (If you use a debugger and set a breakpoint just after the first int 0x80, you will see that it returns with -14 in %eax, which is -EFAULT.)

The second syscall, exit, works OK because the truncation to 32 bits doesn't do any harm in that case.


If you want to pass a 64-bit address to a system call, you will have to use the 64-bit syscall interface:

  • use syscall, not int 0x80;
  • different registers are used: see here;
  • the system call numbers are different as well: see here.

Here is a working version of your code:

.section .text

.globl _start
_start:
movq %rsp, %rbp

movq $1, %rax
movq $1, %rdi
movq 8(%rbp), %rsi # program name address ?
movq $5, %rdx
syscall

movq $60, %rax
movq $0, %rdi
syscall

Linux 64 command line parameters in Assembly

It looks like section 3.4 Process Initialization, and specifically figure 3.9, in the already mentioned System V AMD64 ABI describes precisely what you want to know.

How to start a 64-bit process from a 32-bit process

You can temporarily disable filesystem redirection around the call to Process.Start, the appropriate API's to P/Invoke are Wow64DisableWow64FsRedirection and Wow64RevertWow64FsRedirection.

Another option is to use %windir%\sysnative, which is available on Windows Vista and above.

How does the 64 bit linux kernel kick off a 32 bit process from an ELF

If the execveat system call is used to start a new process, we first enter fs/exec.c in the kernel source into the SYSCALL_DEFINEx(execveat..) function.
This one then calls these functions:

  • do_execveat(..)

    • do_execveat_common(..)

      • exec_binprm(..)

        • search_binary_handler(..)

The search_binary_handler iterates over the various binary handlers. In a 64 bit Linux kernel, there will be one handler for 64 bit ELFs and one for 32 bit ELFs. Both handlers are ultimately built from the same source fs/binfmt_elf.c. However, the 32 bit handler is built via fs/compat_binfmt_elf.c which redefines a number of macros before including the source file binfmt_elf.c itself.

Inside binfmt_elf.c, elf_check_arch is called. This is a macro defined in arch/x86/include/asm/elf.h and defined differently in the 64 bit handler vs the 32 bit handler. For 64 bit, it compares with EM_X86_64 ( 62 - defined in include/uapi/ilnux/elf-em.h). For 32 bit, it compares with EM_386 (3) or EM_486 (6) (defined in the same file). If the comparison fails, the binary handler gives up, so we end up with only one of the handlers taking care of the ELF parsing and execution - depending on whether the ELF is 64 bit or 32 bit.

All differences on parsing 32 bit ELFs vs 64 bit ELFs in 64 bit Linux should therefore be found in the file fs/compat_binfmt_elf.c.

The main clue seems to be compat_start_thread. start_thread is redefined to compat_start_thread. This function definition is found in arch/x86/kernel/process_64.c. compat_start_thread then calls start_thread_common with these arguments:

start_thread_common(regs, new_ip, new_sp,
test_thread_flag(TIF_X32)
? __USER_CS : __USER32_CS,
__USER_DS, __USER_DS);

while the normal start_thread function calls start_thread_common with these arguments:

start_thread_common(regs, new_ip, new_sp,
__USER_CS, __USER_DS, 0);

Here we already see the architecture dependent code doing something with CS differently for 64 bit ELFs vs 32 bit ELFs.

Then we have the definitions for __USER_CS and __USER32_CS in arch/x86/include/asm/segment.h:

#define __USER_CS           (GDT_ENTRY_DEFAULT_USER_CS*8 + 3)
#define __USER32_CS (GDT_ENTRY_DEFAULT_USER32_CS*8 + 3)

and:

#define GDT_ENTRY_DEFAULT_USER_CS   6
#define GDT_ENTRY_DEFAULT_USER32_CS 4

So __USER_CS is 6*8 + 3 = 51 = 0x33

And __USER32_CS is 4*8 + 3 = 35 = 0x23

These numbers match what is used for CS in these examples:

  • For going from 64 bit mode to 32 bit in the middle of a process
  • For going from 32 bit mode to 64 bit in the middle of a process

Since the CPU is not running in real mode, the segment register is not filled with the segment itself, but a 16-bit selector:

From Wikipedia (Protected mode):

In protected mode, the segment_part is replaced by a 16-bit selector, in which the 13 upper bits (bit 3 to bit 15) contain the index of an entry inside a descriptor table. The next bit (bit 2) specifies whether the operation is used with the GDT or the LDT. The lowest two bits (bit 1 and bit 0) of the selector are combined to define the privilege of the request, where the values of 0 and 3 represent the highest and the lowest privilege, respectively.

With the CS value 0x23, bit 1 and 0 is 3, meaning "lowest privilege". Bit 2 is 0, meaning GDT, and bit 3 to bit 15 is 4, meaning we get index 4 from the global descriptor table (GDT).

This is how far I have been able to dig so far.

How to detect which parallel process ends first in Linux?

Sorry to post my own answer, but I just found a solution. This works:

echo $(./known & echo x$(./unknown))

Here, 'x' is what differentiates the two outputs, so even if they are the same, I know which one was printed first.

Please feel free to answer or comment if you have a better solution. Thanks.

Linux `top` command: how much process memory is physically stored in swap space?

The behavior depends on a version of procps you are using. For instance, in version 3.0.5 SWAP value equals:

task->size - task->resident

and it is exactly what you are encountering. Man top.1 says:

VIRT = SWAP + RES

Procps-ng, however, reads /proc/pid/status and sets SWAP correctly

https://gitlab.com/procps-ng/procps/blob/master/proc/readproc.c#L383

So, you can update procps or look at /proc/pid/status directly

Peak memory usage of a linux/unix process

Here's a one-liner that doesn't require any external scripts or utilities and doesn't require you to start the process via another program like Valgrind or time, so you can use it for any process that's already running:

grep ^VmPeak /proc/$PID/status

(replace $PID with the PID of the process you're interested in)



Related Topics



Leave a reply



Submit