kernel: use 64-bit virtual entry point for expanded header, document behaviour in a.out(6)

For 64-bit architectures, the a.out header has the HDR_MAGIC flag set
in the magic and is expanded by 8 bytes containing the 64-bit virtual
address of the programs entry point. While Exec.entry contains physical
address for kernel images.

Our sysexec() would always use Exec.entry, even for 64-bit a.out binaries,
which worked because PADDR(entry) == entry for userspace pointers.

This change fixes it, having the kernel use the 64-bit entry point
and document the behaviour in the manpage.
front
cinap_lenrek 2021-05-29 14:18:35 +02:00
parent d168b89ab1
commit c2297ce5c1
4 changed files with 91 additions and 60 deletions

View File

@ -25,7 +25,7 @@ typedef struct Exec {
long pcsz; /* size of pc/line number table */
} Exec;
#define HDR_MAGIC 0x00008000
#define HDR_MAGIC 0x00008000 /* header expansion */
#define _MAGIC(f, b) ((f)|((((4*(b))+0)*(b))+7))
#define A_MAGIC _MAGIC(0, 8) /* 68020 */
@ -62,7 +62,18 @@ The text segment consists of the header and the first
bytes of the binary file.
The
.B entry
field gives the virtual address of the entry point of the program.
field gives the virtual address of the entry point of the program
unless
.B HDR_MAGIC
flag is present in the
.B magic
field.
In that case, the header is expanded
by 8 bytes containing the 64-bit virtual address of the
program entry point and the 32-bit
.B entry
field is reserved for physical kernel entry point.
.PP
The data segment starts at the first page-rounded virtual address
after the text segment.
It consists of the next

View File

@ -10,6 +10,8 @@ Block* allocb(int);
int anyhigher(void);
int anyready(void);
Image* attachimage(int, Chan*, uintptr, ulong);
ulong beswal(ulong);
uvlong beswav(uvlong);
int blocklen(Block*);
void bootlinks(void);
void cachedel(Image*, uintptr);

View File

@ -6,16 +6,6 @@
#include "../port/error.h"
#include "a.out.h"
static ulong
l2be(long l)
{
uchar *cp;
cp = (uchar*)&l;
return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3];
}
static void
readn(Chan *c, void *vp, long n)
{
@ -35,8 +25,11 @@ readn(Chan *c, void *vp, long n)
void
rebootcmd(int argc, char *argv[])
{
struct {
Exec;
uvlong hdr[1];
} ehdr;
Chan *c;
Exec exec;
ulong magic, text, rtext, entry, data, size, align;
uchar *p;
@ -49,11 +42,11 @@ rebootcmd(int argc, char *argv[])
nexterror();
}
readn(c, &exec, sizeof(Exec));
magic = l2be(exec.magic);
entry = l2be(exec.entry);
text = l2be(exec.text);
data = l2be(exec.data);
readn(c, &ehdr, sizeof(Exec));
magic = beswal(ehdr.magic);
entry = beswal(ehdr.entry);
text = beswal(ehdr.text);
data = beswal(ehdr.data);
if(!(magic == AOUT_MAGIC)){
switch(magic){
@ -66,7 +59,7 @@ rebootcmd(int argc, char *argv[])
}
}
if(magic & HDR_MAGIC)
readn(c, &exec, 8);
readn(c, ehdr.hdr, sizeof(ehdr.hdr));
switch(magic){
case R_MAGIC:

View File

@ -234,6 +234,8 @@ shargs(char *s, int n, char **ap)
{
int i;
if(n <= 2 || s[0] != '#' || s[1] != '!')
return -1;
s += 2;
n -= 2; /* skip #! */
for(i=0;; i++){
@ -261,27 +263,42 @@ shargs(char *s, int n, char **ap)
return i;
}
static ulong
l2be(long l)
ulong
beswal(ulong l)
{
uchar *cp;
uchar *p;
cp = (uchar*)&l;
return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3];
p = (uchar*)&l;
return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
}
uvlong
beswav(uvlong v)
{
uchar *p;
p = (uchar*)&v;
return ((uvlong)p[0]<<56) | ((uvlong)p[1]<<48) | ((uvlong)p[2]<<40)
| ((uvlong)p[3]<<32) | ((uvlong)p[4]<<24)
| ((uvlong)p[5]<<16) | ((uvlong)p[6]<<8)
| (uvlong)p[7];
}
uintptr
sysexec(va_list list)
{
Exec exec;
char line[sizeof(Exec)];
struct {
Exec;
uvlong hdr[1];
} ehdr;
char line[sizeof(ehdr)];
char *progarg[sizeof(line)/2+1];
volatile char *args, *elem, *file0;
char **argv, **argp, **argp0;
char *a, *e, *charp, *file;
int i, n, indir;
ulong magic, ssize, nargs, nbytes;
uintptr t, d, b, entry, bssend, text, data, bss, tstk, align;
uintptr t, d, b, entry, text, data, bss, bssend, tstk, align;
Segment *s, *ts;
Image *img;
Tos *tos;
@ -311,7 +328,7 @@ sysexec(va_list list)
}
nexterror();
}
align = BY2PG;
align = BY2PG-1;
indir = 0;
file = file0;
for(;;){
@ -323,39 +340,47 @@ sysexec(va_list list)
if(!indir)
kstrdup(&elem, up->genbuf);
n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0);
if(n <= 2)
error(Ebadexec);
magic = l2be(exec.magic);
if(n == sizeof(Exec) && (magic == AOUT_MAGIC)){
entry = l2be(exec.entry);
text = l2be(exec.text);
if(magic & HDR_MAGIC)
text += 8;
switch(magic){
case S_MAGIC: /* 2MB segment alignment for amd64 */
align = 0x200000;
break;
case V_MAGIC: /* 16K segment alignment for mips */
align = 0x4000;
break;
case R_MAGIC: /* 64K segment alignment for arm64 */
align = 0x10000;
break;
n = devtab[tc->type]->read(tc, &ehdr, sizeof(ehdr), 0);
if(n >= sizeof(Exec)) {
magic = beswal(ehdr.magic);
if(magic == AOUT_MAGIC) {
if(magic & HDR_MAGIC) {
if(n < sizeof(ehdr))
error(Ebadexec);
entry = beswav(ehdr.hdr[0]);
text = UTZERO+sizeof(ehdr);
} else {
entry = beswal(ehdr.entry);
text = UTZERO+sizeof(Exec);
}
if(entry < text)
error(Ebadexec);
text += beswal(ehdr.text);
if(text <= entry || text >= (USTKTOP-USTKSIZE))
error(Ebadexec);
switch(magic){
case S_MAGIC: /* 2MB segment alignment for amd64 */
align = 0x1fffff;
break;
case V_MAGIC: /* 16K segment alignment for mips */
align = 0x3fff;
break;
case R_MAGIC: /* 64K segment alignment for arm64 */
align = 0xffff;
break;
}
break; /* for binary */
}
if(text >= (USTKTOP-USTKSIZE)-(UTZERO+sizeof(Exec))
|| entry < UTZERO+sizeof(Exec)
|| entry >= UTZERO+sizeof(Exec)+text)
error(Ebadexec);
break; /* for binary */
}
if(indir++)
error(Ebadexec);
/*
* Process #! /bin/sh args ...
*/
memmove(line, &exec, n);
if(line[0]!='#' || line[1]!='!' || indir++)
error(Ebadexec);
memmove(line, &ehdr, n);
n = shargs(line, n, progarg);
if(n < 1)
error(Ebadexec);
@ -371,10 +396,10 @@ sysexec(va_list list)
cclose(tc);
}
data = l2be(exec.data);
bss = l2be(exec.bss);
align--;
t = (UTZERO+sizeof(Exec)+text+align) & ~align;
t = (text+align) & ~align;
text -= UTZERO;
data = beswal(ehdr.data);
bss = beswal(ehdr.bss);
align = BY2PG-1;
d = (t + data + align) & ~align;
bssend = t + data + bss;
@ -518,7 +543,7 @@ sysexec(va_list list)
up->seg[TSEG] = ts;
ts->flushme = 1;
ts->fstart = 0;
ts->flen = sizeof(Exec)+text;
ts->flen = text;
unlock(img);
/* Data. Shared. */