Add AT_PLATFORM, AT_HWCAP and AT_CLKTCK auxiliary vector entries which

are used by glibc. This silents the message "2.4+ kernel w/o ELF notes?"
from some programs at start, among them are top and pkill.

Do the assignment of the vector entries in elf_linux_fixup()
as it is done in glibc.

Fix some minor style issues.

Submitted by:	Marcin Cieslak <saper at SYSTEM PL>
Approved by:	kib (mentor)
MFC after:	1 week
This commit is contained in:
Dmitry Chagin 2009-03-04 12:14:33 +00:00
parent 09efd0ec6a
commit 4d7c2e8a48
6 changed files with 218 additions and 51 deletions

View File

@ -108,6 +108,10 @@ typedef struct {
#define LINUX_CTL_MAXNAME 10
#define LINUX_AT_COUNT 16 /* Count of used aux entry types.
* Keep this synchronized with
* elf_linux_fixup() code.
*/
struct l___sysctl_args
{
l_uintptr_t name;

View File

@ -78,6 +78,7 @@ __FBSDID("$FreeBSD$");
#include <amd64/linux32/linux32_proto.h>
#include <compat/linux/linux_emul.h>
#include <compat/linux/linux_mib.h>
#include <compat/linux/linux_misc.h>
#include <compat/linux/linux_signal.h>
#include <compat/linux/linux_util.h>
@ -106,6 +107,8 @@ MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
#define LINUX_SYS_linux_rt_sendsig 0
#define LINUX_SYS_linux_sendsig 0
const char *linux_platform = "i686";
static int linux_szplatform;
extern char linux_sigcode[];
extern int linux_szsigcode;
@ -246,7 +249,12 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
{
Elf32_Auxargs *args;
Elf32_Addr *base;
Elf32_Addr *pos;
Elf32_Addr *pos, *uplatform;
struct linux32_ps_strings *arginfo;
arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS;
uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szsigcode -
linux_szplatform);
KASSERT(curthread->td_proc == imgp->proc,
("unsafe elf_linux_fixup(), should be curproc"));
@ -254,8 +262,8 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
args = (Elf32_Auxargs *)imgp->auxargs;
pos = base + (imgp->args->argc + imgp->args->envc + 2);
if (args->execfd != -1)
AUXARGS_ENTRY_32(pos, AT_EXECFD, args->execfd);
AUXARGS_ENTRY_32(pos, LINUX_AT_HWCAP, cpu_feature);
AUXARGS_ENTRY_32(pos, LINUX_AT_CLKTCK, hz);
AUXARGS_ENTRY_32(pos, AT_PHDR, args->phdr);
AUXARGS_ENTRY_32(pos, AT_PHENT, args->phent);
AUXARGS_ENTRY_32(pos, AT_PHNUM, args->phnum);
@ -263,10 +271,14 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
AUXARGS_ENTRY_32(pos, AT_FLAGS, args->flags);
AUXARGS_ENTRY_32(pos, AT_ENTRY, args->entry);
AUXARGS_ENTRY_32(pos, AT_BASE, args->base);
AUXARGS_ENTRY_32(pos, LINUX_AT_SECURE, 0);
AUXARGS_ENTRY_32(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
AUXARGS_ENTRY_32(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
AUXARGS_ENTRY_32(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
AUXARGS_ENTRY_32(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
AUXARGS_ENTRY_32(pos, LINUX_AT_PLATFORM, PTROUT(uplatform));
if (args->execfd != -1)
AUXARGS_ENTRY_32(pos, AT_EXECFD, args->execfd);
AUXARGS_ENTRY_32(pos, AT_NULL, 0);
free(imgp->auxargs, M_TEMP);
@ -857,23 +869,27 @@ linux_copyout_strings(struct image_params *imgp)
char *stringp, *destp;
u_int32_t *stack_base;
struct linux32_ps_strings *arginfo;
int sigcodesz;
/*
* Calculate string base and vector table pointers.
* Also deal with signal trampoline code for this exec type.
*/
arginfo = (struct linux32_ps_strings *)LINUX32_PS_STRINGS;
sigcodesz = *(imgp->proc->p_sysent->sv_szsigcode);
destp = (caddr_t)arginfo - sigcodesz - SPARE_USRSPACE -
roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *));
destp = (caddr_t)arginfo - linux_szsigcode - SPARE_USRSPACE -
linux_szplatform - roundup((ARG_MAX - imgp->args->stringspace),
sizeof(char *));
/*
* install sigcode
*/
if (sigcodesz)
copyout(imgp->proc->p_sysent->sv_sigcode,
((caddr_t)arginfo - sigcodesz), sigcodesz);
copyout(imgp->proc->p_sysent->sv_sigcode,
((caddr_t)arginfo - linux_szsigcode), linux_szsigcode);
/*
* Install LINUX_PLATFORM
*/
copyout(linux_platform, ((caddr_t)arginfo - linux_szsigcode -
linux_szplatform), linux_szplatform);
/*
* If we have a valid auxargs ptr, prepare some room
@ -885,7 +901,7 @@ linux_copyout_strings(struct image_params *imgp)
* lower compatibility.
*/
imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size :
(AT_COUNT * 2);
(LINUX_AT_COUNT * 2);
/*
* The '+ 2' is for the null pointers at the end of each of
* the arg and env vector sets,and imgp->auxarg_size is room
@ -919,14 +935,14 @@ linux_copyout_strings(struct image_params *imgp)
/*
* Fill in "ps_strings" struct for ps, w, etc.
*/
suword32(&arginfo->ps_argvstr, (u_int32_t)(intptr_t)vectp);
suword32(&arginfo->ps_argvstr, (uint32_t)(intptr_t)vectp);
suword32(&arginfo->ps_nargvstr, argc);
/*
* Fill in argument portion of vector table.
*/
for (; argc > 0; --argc) {
suword32(vectp++, (u_int32_t)(intptr_t)destp);
suword32(vectp++, (uint32_t)(intptr_t)destp);
while (*stringp++ != 0)
destp++;
destp++;
@ -935,14 +951,14 @@ linux_copyout_strings(struct image_params *imgp)
/* a null vector table pointer separates the argp's from the envp's */
suword32(vectp++, 0);
suword32(&arginfo->ps_envstr, (u_int32_t)(intptr_t)vectp);
suword32(&arginfo->ps_envstr, (uint32_t)(intptr_t)vectp);
suword32(&arginfo->ps_nenvstr, envc);
/*
* Fill in environment portion of vector table.
*/
for (; envc > 0; --envc) {
suword32(vectp++, (u_int32_t)(intptr_t)destp);
suword32(vectp++, (uint32_t)(intptr_t)destp);
while (*stringp++ != 0)
destp++;
destp++;
@ -1089,6 +1105,8 @@ linux_elf_modevent(module_t mod, int type, void *data)
linux_schedtail, NULL, 1000);
linux_exec_tag = EVENTHANDLER_REGISTER(process_exec,
linux_proc_exec, NULL, 1000);
linux_szplatform = roundup(strlen(linux_platform) + 1,
sizeof(char *));
if (bootverbose)
printf("Linux ELF exec handler installed\n");
} else

View File

@ -92,10 +92,6 @@ __FBSDID("$FreeBSD$");
#include <compat/linux/linux_emul.h>
#include <compat/linux/linux_misc.h>
#ifdef __i386__
#include <machine/cputypes.h>
#endif
#define BSD_TO_LINUX_SIGNAL(sig) \
(((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig)
@ -731,34 +727,8 @@ linux_newuname(struct thread *td, struct linux_newuname_args *args)
*p = '\0';
break;
}
#ifdef __i386__
{
const char *class;
strlcpy(utsname.machine, linux_platform, LINUX_MAX_UTSNAME);
switch (cpu_class) {
case CPUCLASS_686:
class = "i686";
break;
case CPUCLASS_586:
class = "i586";
break;
case CPUCLASS_486:
class = "i486";
break;
default:
class = "i386";
}
strlcpy(utsname.machine, class, LINUX_MAX_UTSNAME);
}
#elif defined(__amd64__) /* XXX: Linux can change 'personality'. */
#ifdef COMPAT_LINUX32
strlcpy(utsname.machine, "i686", LINUX_MAX_UTSNAME);
#else
strlcpy(utsname.machine, "x86_64", LINUX_MAX_UTSNAME);
#endif /* COMPAT_LINUX32 */
#else /* something other than i386 or amd64 - assume we and Linux agree */
strlcpy(utsname.machine, machine, LINUX_MAX_UTSNAME);
#endif /* __i386__ */
mtx_lock(&hostname_mtx);
strlcpy(utsname.domainname, V_domainname, LINUX_MAX_UTSNAME);
mtx_unlock(&hostname_mtx);

View File

@ -45,4 +45,19 @@
#define LINUX_MREMAP_MAYMOVE 1
#define LINUX_MREMAP_FIXED 2
extern const char *linux_platform;
/*
* Non-standard aux entry types used in Linux ELF binaries.
*/
#define LINUX_AT_PLATFORM 15 /* String identifying CPU */
#define LINUX_AT_HWCAP 16 /* CPU capabilities */
#define LINUX_AT_CLKTCK 17 /* frequency at which times() increments */
#define LINUX_AT_SECURE 23 /* secure mode boolean */
#define LINUX_AT_BASE_PLATFORM 24 /* string identifying real platform, may
* differ from AT_PLATFORM.
*/
#define LINUX_AT_EXECFN 31 /* filename of program */
#endif /* _LINUX_MISC_H_ */

View File

@ -102,6 +102,10 @@ typedef struct {
#define LINUX_CTL_MAXNAME 10
#define LINUX_AT_COUNT 16 /* Count of used aux entry types.
* Keep this synchronized with
* elf_linux_fixup() code.
*/
struct l___sysctl_args
{
l_int *name;

View File

@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_param.h>
#include <machine/cpu.h>
#include <machine/cputypes.h>
#include <machine/md_var.h>
#include <machine/pcb.h>
@ -65,6 +66,7 @@ __FBSDID("$FreeBSD$");
#include <i386/linux/linux_proto.h>
#include <compat/linux/linux_emul.h>
#include <compat/linux/linux_mib.h>
#include <compat/linux/linux_misc.h>
#include <compat/linux/linux_signal.h>
#include <compat/linux/linux_util.h>
@ -107,6 +109,10 @@ static void linux_prepsyscall(struct trapframe *tf, int *args, u_int *code,
static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask);
static void exec_linux_setregs(struct thread *td, u_long entry,
u_long stack, u_long ps_strings);
static register_t *linux_copyout_strings(struct image_params *imgp);
static int linux_szplatform;
const char *linux_platform;
extern LIST_HEAD(futex_list, futex) futex_list;
extern struct sx futex_sx;
@ -231,22 +237,30 @@ linux_fixup(register_t **stack_base, struct image_params *imgp)
**stack_base = (intptr_t)(void *)argv;
(*stack_base)--;
**stack_base = imgp->args->argc;
return 0;
return (0);
}
static int
elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
{
struct proc *p;
Elf32_Auxargs *args;
Elf32_Addr *uplatform;
struct ps_strings *arginfo;
register_t *pos;
KASSERT(curthread->td_proc == imgp->proc,
("unsafe elf_linux_fixup(), should be curproc"));
p = imgp->proc;
arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
uplatform = (Elf32_Addr *)((caddr_t)arginfo - linux_szsigcode -
linux_szplatform);
args = (Elf32_Auxargs *)imgp->auxargs;
pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2);
if (args->execfd != -1)
AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
AUXARGS_ENTRY(pos, LINUX_AT_HWCAP, cpu_feature);
AUXARGS_ENTRY(pos, LINUX_AT_CLKTCK, hz);
AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
@ -254,10 +268,14 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
AUXARGS_ENTRY(pos, AT_BASE, args->base);
AUXARGS_ENTRY(pos, LINUX_AT_SECURE, 0);
AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
AUXARGS_ENTRY(pos, LINUX_AT_PLATFORM, PTROUT(uplatform));
if (args->execfd != -1)
AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
AUXARGS_ENTRY(pos, AT_NULL, 0);
free(imgp->auxargs, M_TEMP);
@ -265,9 +283,125 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp)
(*stack_base)--;
**stack_base = (register_t)imgp->args->argc;
return 0;
return (0);
}
/*
* Copied from kern/kern_exec.c
*/
static register_t *
linux_copyout_strings(struct image_params *imgp)
{
int argc, envc;
char **vectp;
char *stringp, *destp;
register_t *stack_base;
struct ps_strings *arginfo;
struct proc *p;
/*
* Calculate string base and vector table pointers.
* Also deal with signal trampoline code for this exec type.
*/
p = imgp->proc;
arginfo = (struct ps_strings *)p->p_sysent->sv_psstrings;
destp = (caddr_t)arginfo - linux_szsigcode - SPARE_USRSPACE -
linux_szplatform - roundup((ARG_MAX - imgp->args->stringspace),
sizeof(char *));
/*
* install sigcode
*/
copyout(p->p_sysent->sv_sigcode, ((caddr_t)arginfo -
linux_szsigcode), linux_szsigcode);
/*
* install LINUX_PLATFORM
*/
copyout(linux_platform, ((caddr_t)arginfo - linux_szsigcode -
linux_szplatform), linux_szplatform);
/*
* If we have a valid auxargs ptr, prepare some room
* on the stack.
*/
if (imgp->auxargs) {
/*
* 'AT_COUNT*2' is size for the ELF Auxargs data. This is for
* lower compatibility.
*/
imgp->auxarg_size = (imgp->auxarg_size) ? imgp->auxarg_size :
(LINUX_AT_COUNT * 2);
/*
* The '+ 2' is for the null pointers at the end of each of
* the arg and env vector sets,and imgp->auxarg_size is room
* for argument of Runtime loader.
*/
vectp = (char **)(destp - (imgp->args->argc +
imgp->args->envc + 2 + imgp->auxarg_size) * sizeof(char *));
} else {
/*
* The '+ 2' is for the null pointers at the end of each of
* the arg and env vector sets
*/
vectp = (char **)(destp - (imgp->args->argc + imgp->args->envc + 2) *
sizeof(char *));
}
/*
* vectp also becomes our initial stack base
*/
stack_base = (register_t *)vectp;
stringp = imgp->args->begin_argv;
argc = imgp->args->argc;
envc = imgp->args->envc;
/*
* Copy out strings - arguments and environment.
*/
copyout(stringp, destp, ARG_MAX - imgp->args->stringspace);
/*
* Fill in "ps_strings" struct for ps, w, etc.
*/
suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp);
suword(&arginfo->ps_nargvstr, argc);
/*
* Fill in argument portion of vector table.
*/
for (; argc > 0; --argc) {
suword(vectp++, (long)(intptr_t)destp);
while (*stringp++ != 0)
destp++;
destp++;
}
/* a null vector table pointer separates the argp's from the envp's */
suword(vectp++, 0);
suword(&arginfo->ps_envstr, (long)(intptr_t)vectp);
suword(&arginfo->ps_nenvstr, envc);
/*
* Fill in environment portion of vector table.
*/
for (; envc > 0; --envc) {
suword(vectp++, (long)(intptr_t)destp);
while (*stringp++ != 0)
destp++;
destp++;
}
/* end of vector table is a null pointer */
suword(vectp, 0);
return (stack_base);
}
extern int _ucodesel, _udatasel;
extern unsigned long linux_sznonrtsigcode;
@ -808,6 +942,25 @@ exec_linux_setregs(struct thread *td, u_long entry,
fldcw(&control);
}
static void
linux_get_machine(const char **dst)
{
switch (cpu_class) {
case CPUCLASS_686:
*dst = "i686";
break;
case CPUCLASS_586:
*dst = "i586";
break;
case CPUCLASS_486:
*dst = "i486";
break;
default:
*dst = "i386";
}
}
struct sysentvec linux_sysvec = {
.sv_size = LINUX_SYS_MAXSYSCALL,
.sv_table = linux_sysent,
@ -863,7 +1016,7 @@ struct sysentvec elf_linux_sysvec = {
.sv_usrstack = USRSTACK,
.sv_psstrings = PS_STRINGS,
.sv_stackprot = VM_PROT_ALL,
.sv_copyout_strings = exec_copyout_strings,
.sv_copyout_strings = linux_copyout_strings,
.sv_setregs = exec_linux_setregs,
.sv_fixlimit = NULL,
.sv_maxssiz = NULL,
@ -929,6 +1082,9 @@ linux_elf_modevent(module_t mod, int type, void *data)
NULL, 1000);
linux_exec_tag = EVENTHANDLER_REGISTER(process_exec, linux_proc_exec,
NULL, 1000);
linux_get_machine(&linux_platform);
linux_szplatform = roundup(strlen(linux_platform) + 1,
sizeof(char *));
if (bootverbose)
printf("Linux ELF exec handler installed\n");
} else