hipe segmentation fault
Serge Aleynikov
serge@REDACTED
Fri May 5 15:36:45 CEST 2006
Mikael,
When I applied this patch to FC5 Linux 64-bit OS, Erlang compiled fine,
however when I did the same on a 32-bit Linux FC5 OS, the make process
failed with the errors shown below.
Serge
gcc -g -O3 -I/home/serge/Projects/Distrs/R10B-10/erts/i686-pc-linux-gnu
-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DHYBRID
-DHAVE_CONFIG_H -Wall -Wstrict-prototypes -Wmissing-prototypes
-D_THREAD_SAFE -D_REENTRANT -DUSE_THREADS -Ibeam -Isys/unix
-Isys/common -Ii686-pc-linux-gnu -Ii686-pc-linux-gnu/hybrid -Izlib
-Ihipe -I../include/internal -I../include/internal/i686-pc-linux-gnu -c
hipe/hipe_x86.c -o
/home/serge/Projects/Distrs/R10B-10/erts/obj.hybrid.beam/i686-pc-linux-gnu/hipe_x86.o
hipe/hipe_x86.c: In function 'morecore':
hipe/hipe_x86.c:107: warning: implicit declaration of function 'mmap'
hipe/hipe_x86.c:108: error: 'PROT_EXEC' undeclared (first use in this
function)
hipe/hipe_x86.c:108: error: (Each undeclared identifier is reported only
once
hipe/hipe_x86.c:108: error: for each function it appears in.)
hipe/hipe_x86.c:108: error: 'PROT_READ' undeclared (first use in this
function)
hipe/hipe_x86.c:108: error: 'PROT_WRITE' undeclared (first use in this
function)
hipe/hipe_x86.c:109: error: 'MAP_PRIVATE' undeclared (first use in this
function)
hipe/hipe_x86.c:109: error: 'MAP_ANONYMOUS' undeclared (first use in
this function)
hipe/hipe_x86.c:114: warning: assignment makes pointer from integer
without a cast
hipe/hipe_x86.c:115: error: 'MAP_FAILED' undeclared (first use in this
function)
make[3]: ***
[/home/serge/Projects/Distrs/R10B-10/erts/obj.hybrid.beam/i686-pc-linux-gnu/hipe_x86.o]
Error 1
make[3]: Leaving directory
`/home/serge/Projects/Distrs/R10B-10/erts/emulator'
make[2]: *** [hybrid] Error 2
make[2]: Leaving directory
`/home/serge/Projects/Distrs/R10B-10/erts/emulator'
make[1]: *** [hybrid] Error 2
make[1]: Leaving directory `/home/serge/Projects/Distrs/R10B-10/erts'
make: *** [emulator] Error 2
Mikael Pettersson wrote:
> Serge Aleynikov writes:
> > Mikael,
> >
> > Here's a bunch of info you requested. Let's continue this discussion
> > outside of the mailing list's scope, and just post the resolution
> > when/if it's available.
> >
> [gdb session omitted]
>
> Problem solved. According to the gdb session everything looked OK,
> yet the code couldn't be executed. It turns out that with the fairly
> new processor model Serge is using, the Linux kernel makes normal
> data memory non-executable by default. We've seen this long ago on
> AMD64 machines with 64-bit kernels, but never before on machines with
> 32-bit kernels. The solution is to adapt the specially written AMD64
> code memory allocation routines for use on x86 as well.
>
> The patch below solves this problem. It's been checked in on the R11
> development branch and should be applied to R10B-10 as well.
>
> /Mikael
>
> --- otp-0330/erts/emulator/hipe/hipe_amd64.h.~1~ 2005-12-15 12:29:52.000000000 +0100
> +++ otp-0330/erts/emulator/hipe/hipe_amd64.h 2006-04-06 17:46:19.000000000 +0200
> @@ -14,10 +14,6 @@
>
> #define hipe_arch_name am_amd64
>
> -/* for hipe_bifs_enter_code_2 */
> -extern void *hipe_alloc_code(Uint nrbytes, Eterm callees, Eterm *trampolines, Process *p);
> -#define HIPE_ALLOC_CODE(n,c,t,p) hipe_alloc_code((n),(c),(t),(p))
> -
> extern const Uint sse2_fnegate_mask[];
>
> #endif /* HIPE_AMD64_H */
> --- otp-0330/erts/emulator/hipe/hipe_x86.c.~1~ 2005-12-15 12:29:53.000000000 +0100
> +++ otp-0330/erts/emulator/hipe/hipe_x86.c 2006-04-06 19:23:59.000000000 +0200
> @@ -50,6 +50,114 @@
> return 0;
> }
>
> +/*
> + * Memory allocator for executable code.
> + *
> + * This is required on x86 because some combinations
> + * of Linux kernels and CPU generations default to
> + * non-executable memory mappings, causing ordinary
> + * malloc() memory to be non-executable.
> + */
> +static unsigned int code_bytes;
> +static char *code_next;
> +
> +#if 0 /* change to non-zero to get allocation statistics at exit() */
> +static unsigned int total_mapped, nr_joins, nr_splits, total_alloc, nr_allocs, nr_large, total_lost;
> +static unsigned int atexit_done;
> +
> +static void alloc_code_stats(void)
> +{
> + printf("\r\nalloc_code_stats: %u bytes mapped, %u joins, %u splits, %u bytes allocated, %u average alloc, %u large allocs, %u bytes lost\r\n",
> + total_mapped, nr_joins, nr_splits, total_alloc, nr_allocs ? total_alloc/nr_allocs : 0, nr_large, total_lost);
> +}
> +
> +static void atexit_alloc_code_stats(void)
> +{
> + if (!atexit_done) {
> + atexit_done = 1;
> + (void)atexit(alloc_code_stats);
> + }
> +}
> +
> +#define ALLOC_CODE_STATS(X) do{X;}while(0)
> +#else
> +#define ALLOC_CODE_STATS(X) do{}while(0)
> +#endif
> +
> +static void morecore(unsigned int alloc_bytes)
> +{
> + unsigned int map_bytes;
> + char *map_hint, *map_start;
> +
> + /* Page-align the amount to allocate. */
> + map_bytes = (alloc_bytes + 4095) & ~4095;
> +
> + /* Round up small allocations. */
> + if (map_bytes < 1024*1024)
> + map_bytes = 1024*1024;
> + else
> + ALLOC_CODE_STATS(++nr_large);
> +
> + /* Create a new memory mapping, ensuring it is executable
> + and in the low 2GB of the address space. Also attempt
> + to make it adjacent to the previous mapping. */
> + map_hint = code_next + code_bytes;
> + if ((unsigned long)map_hint & 4095)
> + abort();
> + map_start = mmap(map_hint, map_bytes,
> + PROT_EXEC|PROT_READ|PROT_WRITE,
> + MAP_PRIVATE|MAP_ANONYMOUS
> +#ifdef __x86_64__
> + |MAP_32BIT
> +#endif
> + ,
> + -1, 0);
> + if (map_start == MAP_FAILED) {
> + perror("mmap");
> + abort();
> + }
> + ALLOC_CODE_STATS(total_mapped += map_bytes);
> +
> + /* Merge adjacent mappings, so the trailing portion of the previous
> + mapping isn't lost. In practice this is quite successful. */
> + if (map_start == map_hint) {
> + ALLOC_CODE_STATS(++nr_joins);
> + code_bytes += map_bytes;
> + } else {
> + ALLOC_CODE_STATS(++nr_splits);
> + ALLOC_CODE_STATS(total_lost += code_bytes);
> + code_next = map_start;
> + code_bytes = map_bytes;
> + }
> +
> + ALLOC_CODE_STATS(atexit_alloc_code_stats());
> +}
> +
> +static void *alloc_code(unsigned int alloc_bytes)
> +{
> + void *res;
> +
> + /* Align function entries. */
> + alloc_bytes = (alloc_bytes + 3) & ~3;
> +
> + if (code_bytes < alloc_bytes)
> + morecore(alloc_bytes);
> + ALLOC_CODE_STATS(++nr_allocs);
> + ALLOC_CODE_STATS(total_alloc += alloc_bytes);
> + res = code_next;
> + code_next += alloc_bytes;
> + code_bytes -= alloc_bytes;
> + return res;
> +}
> +
> +void *hipe_alloc_code(Uint nrbytes, Eterm callees, Eterm *trampolines, Process *p)
> +{
> + if (is_not_nil(callees))
> + return NULL;
> + *trampolines = NIL;
> + return alloc_code(nrbytes);
> +}
> +
> /* called from hipe_bif0.c:hipe_bifs_make_native_stub_2()
> and hipe_bif0.c:hipe_make_stub() */
> void *hipe_make_native_stub(void *beamAddress, unsigned int beamArity)
> @@ -76,7 +184,7 @@
> 16 + /* 16 when both offsets are 8-bit */
> (P_BEAM_IP >= 128 ? 3 : 0) +
> (P_ARITY >= 128 ? 3 : 0);
> - codep = code = erts_alloc(ERTS_ALC_T_HIPE, codeSize);
> + codep = code = alloc_code(codeSize);
>
> /* movl $beamAddress, P_BEAM_IP(%ebp); 3 or 6 bytes, plus 4 */
> codep[0] = 0xc7;
> --- otp-0330/erts/emulator/hipe/hipe_x86.h.~1~ 2005-12-15 12:29:53.000000000 +0100
> +++ otp-0330/erts/emulator/hipe/hipe_x86.h 2006-04-06 17:45:48.000000000 +0200
> @@ -39,4 +39,8 @@
> extern void nbif_inc_stack_0(void);
> extern void nbif_handle_fp_exception(void);
>
> +/* for hipe_bifs_enter_code_2 */
> +extern void *hipe_alloc_code(Uint nrbytes, Eterm callees, Eterm *trampolines, Process *p);
> +#define HIPE_ALLOC_CODE(n,c,t,p) hipe_alloc_code((n),(c),(t),(p))
> +
> #endif /* HIPE_X86_H */
>
--
Serge Aleynikov
R&D Telecom, IDT Corp.
Tel: (973) 438-3436
Fax: (973) 438-1464
serge@REDACTED
More information about the erlang-questions
mailing list