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
, notint 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(..)
- exec_binprm(..)
- do_execveat_common(..)
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
How to Develop Opengl Es (Gles) 2.0 Applications on Linux
How to Pass a Value to a Builtin Linux Kernel Module at Boot Time
How to Download the Torvalds Linux Kernel Master, (Re)Compile It, and Boot It with Qemu
Why Is Crond Failing to Run a Non-Root Crontab on Alpine Linux
Cuda Performance Penalty When Running in Windows
Find and Remove Files with Space Using Find Command on Linux
How Bash Handles the Jobs When Logout
Why Is Pr_Debug of the Linux Kernel Not Giving Any Output
Use a C Library in Swift on Linux
Getting "I Won't Open a Connection To" When Connecting to Ftp Server from Google Compute Engine
Find All Files Matching 'Name' on Linux System, and Search with Them for 'Text'
How to Use Awk to Convert All the Lower-Case Letters into Upper-Case
What Does "|" Mean in a Terminal Command Line
Accessing the Gpio (Of a Raspberry Pi) Without ''Sudo''
Linux Kernel - Add System Call Dynamically Through Module
Execve Shellcode Linux Segmentation Fault