Bug 124134

Summary: [kernel] The kernel doesn't follow the calling convention in the SVR4/i386 ABI
Product: Base System Reporter: Pedro F. Giffuni <pfgshield-freebsd>
Component: amd64Assignee: freebsd-amd64 (Nobody) <amd64>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: Unspecified   
Hardware: Any   
OS: Any   

Description Pedro F. Giffuni 2008-05-30 15:10:03 UTC
While porting glibc to FreeBSD it was found that FreeBSD doesn't strictly
conform to the SVR4 ABI on AMD64:

http://www.x86-64.org/documentation/abi.pdf (see startup calling convention in 3.4.1.)

Further explanation from Petr Salinger:

/* This is the canonical entry point, usually the first thing in the text
    segment.  The SVR4/i386 ABI (pages 3-31, 3-32) says that when the entry
    point runs, most registers' values are unspecified, except for a few.
    Blindly applied on amd64:

    %rdx         Contains a function pointer to be registered with `atexit'.
                 This is how the dynamic linker arranges to have DT_FINI
                 functions called for shared libraries that have been loaded
                 before this code runs.

    %rsp         The stack contains the arguments and environment:
                 0(%rsp)                 argc
                 8(%rsp)                 argv[0]
                 ...
                 (8*argc)(%rsp)          NULL
                 (8*(argc+1))(%rsp)      envp[0]
                 ...
                                         NULL

    But on amd64 %rsp also have to be 16-byte aligned,
    standard C calling convention already passes arguments in registers.

    FreeBSD uses %edi as pointer to arguments and environment, %rsp is passed aligned.
    On entry from kernel, %rsp=%rdi or %rsp=%rdi-8,
    on entry from ld.so, glibc might set up it slightly differently.

    On FreeBSD, we use %rsi for passing function pointer to rtld_fini().
    On entry from FreeBSD kernel, %rsi is cleared, %rdx is not cleared,
    on entry from ld.so, glibc sets both %rsi and %rdx to point to rtld_fini().

    Used interface (via %rdi, %rsi) is equal to standard C calling interface for

    void _start(void *arg, void *rtld_fini());

*/

Fix: 

It can be workaround in FreeBSD kernel by following both standards
simultaneously, i.e. on entry from kernel after exec() should be %rsp=%rdi
and %rdx=%rsi, and %rsp should be properly aligned.
How-To-Repeat: http://lists.debian.org/debian-bsd/2006/02/msg00223.html
Comment 1 Andriy Gapon freebsd_committer freebsd_triage 2010-12-05 13:54:58 UTC
State Changed
From-To: open->closed

I don't think that this is na issue for the current codebase. 
If I am wrong, please follow up and/or re-open the PR.
Comment 2 Pedro F. Giffuni 2010-12-05 15:08:07 UTC
The code has certainly changed a lot  ...=0A=0AReading the posting on the l=
ink with a possible fix:=0A=0A"...=0ACan you try to add to kernel sources, =
into file sys/amd64/amd64/machdep.c=0Afunction exec_setregs(td, entry, stac=
k, ps_strings)=0Asomewhere at the end=0A=0A=09pcb->pcb_flags |=3D PCB_FULLC=
TX;=0A... "=0A=0AWe don't have anything similar to this in exec_setregs(), =
and from my understanding the issue could not be easily fixed without break=
ing binary compatibility so I would think the issue is still there.=0A=0ATh=
is PR was only for reference though as it doesn't cause trouble for us: I'm=
 OK with the PR being closed.=0A=0A=0A=0A
Comment 3 Kostik Belousov 2010-12-05 17:24:55 UTC
On Sun, Dec 05, 2010 at 07:08:07AM -0800, pfgshield-freebsd@yahoo.com wrote:
> The code has certainly changed a lot  ...
> 
> Reading the posting on the link with a possible fix:
> 
> "...
> Can you try to add to kernel sources, into file sys/amd64/amd64/machdep.c
> function exec_setregs(td, entry, stack, ps_strings)
> somewhere at the end
> 
> 	pcb->pcb_flags |= PCB_FULLCTX;
> ... "
> 
> We don't have anything similar to this in exec_setregs(), and from my understanding the issue could not be easily fixed without breaking binary compatibility so I would think the issue is still there.
> 
> This PR was only for reference though as it doesn't cause trouble for us: I'm OK with the PR being closed.
> 


I looked at the PR before. Looking again now, I have the same conclusion,
that is I do not understand what is the issue.

On the first return into usermode after the successfull execve(2), kernel
sets the following registers:
- %rsp (properly aligned)
- %rdi (1st parameter in usermode ABI; contains the pointer to startup
  frame, i.e. &argc)
- all other GP registers are zeroed.

ABI rev. 0.99 requires the following setup:
- %rsp properly aligned and has the value &argc
- %rdx points to a function to be registered with atexit(3), or NULL.

We do satisfy the ABI requirement for %rdx content in the trivial way,
by passing 0.

The layout of the startup frame also seems conforming.
Comment 4 dfilter service freebsd_committer freebsd_triage 2010-12-06 15:15:33 UTC
Author: kib
Date: Mon Dec  6 15:15:27 2010
New Revision: 216231
URL: http://svn.freebsd.org/changeset/base/216231

Log:
  Do not leak %rdx value in the previous image to the new image after
  execve(2). Note that ia32 binaries already handle this properly,
  since ia32_setregs() resets td_retval[1], but not exec_setregs().
  
  We still do not conform to the amd64 ABI specification, since %rsp
  on the image startup is not aligned to 16 bytes.
  
  PR:	amd64/124134
  Discussed with:	Petr Salinger <Petr.Salinger seznam cz>
  	(who convinced me that there is indeed several bugs)
  MFC after:	1 week

Modified:
  head/sys/amd64/amd64/machdep.c

Modified: head/sys/amd64/amd64/machdep.c
==============================================================================
--- head/sys/amd64/amd64/machdep.c	Mon Dec  6 12:18:02 2010	(r216230)
+++ head/sys/amd64/amd64/machdep.c	Mon Dec  6 15:15:27 2010	(r216231)
@@ -876,6 +876,7 @@ exec_setregs(struct thread *td, struct i
 	regs->tf_fs = _ufssel;
 	regs->tf_gs = _ugssel;
 	regs->tf_flags = TF_HASSEGS;
+	td->td_retval[1] = 0;
 
 	/*
 	 * Reset the hardware debug registers if they were in use.
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"