From Juergen Kreileder of Blackdown.
I've found the problem that caused crashes with SuSE's 2.4.21 AMD64
kernel:
,----[ Excerpt from linux-2.6.0-test10/Documentation/x86_64/boot-options.txt ]
| Non Executable Mappings
|
| noexec=on|off
|
| on Enable
| off Disable
| noforce (default) Don't enable by default for heap/stack/data,
| but allow PROT_EXEC to be effective
|
| noexec32=opt{,opt}
|
| Control the no exec default for 32bit processes.
| Requires noexec=on or noexec=noforce to be effective.
|
| Valid options:
| all,on Heap,stack,data is non executable.
| off (default) Heap,stack,data is executable
| stack Stack is non executable, heap/data is.
| force Don't imply PROT_EXEC for PROT_READ
| compat (default) Imply PROT_EXEC for PROT_READ
`----
2.4.21 doesn't have that documentation bit but it has the code for
this feature. The 'noforce' setting seems to be a bit broken, on my
UP system (512) most code still worked, on my SMP machine (1024M) I
got crashes immediately when starting java.
The problematic code piece an AMD64 were the signature handlers:
allocated out of the heap but not marked executable.
Somebody apparently thought of this problem before and had already
added a call to os::unguard_memory(). But he missed the fact that the
Linux implementation (mprotect(2)) expects a page size aligned address.
Here's a fix for AMD64 (blatantly stolen from the IA64 version):
--- interpreterRT_amd64.cpp 25 Nov 2003 15:57:50 -0000 1.1.1.2
+++ interpreterRT_amd64.cpp 15 Dec 2003 07:03:32 -0000
@@ -276,9 +276,16 @@
: public AllStatic
{
public:
- enum { size = 1024 }; // the size of the temporary code buffer
+ enum { size = 1 * K }; // the size of the temporary code buffer
+ enum { blob_size = 1 * K }; // the size of a handler code blob
private:
+ // the current buffer blob containing the generated handlers
+ static BufferBlob* _handler_blob;
+
+ // next available address within _handler_blob;
+ static address _handler;
+
// the fingerprint collection
static GrowableArray<uint64_t>* _fingerprints;
@@ -288,15 +295,43 @@
// the temporary code buffer
static u_char _buffer[SignatureHandlerLibrary::size];
+ static address set_handler_blob()
+ {
+ BufferBlob* handler_blob = BufferBlob::create(blob_size,
+ "native signature handlers");
+ if (handler_blob == NULL) {
+ fatal1("CodeCache: no room for %s", "native signature handlers");
+ }
+ address handler = handler_blob->instructions_begin();
+ _handler_blob = handler_blob;
+ _handler = handler;
+ return handler;
+ }
+
static void initialize()
{
if (_fingerprints != NULL) {
return;
}
+ (void) set_handler_blob();
_fingerprints = new(ResourceObj::C_HEAP)GrowableArray<uint64_t>(32, true);
- _handlers = new(ResourceObj::C_HEAP)GrowableArray<address >(32, true);
+ _handlers = new(ResourceObj::C_HEAP)GrowableArray<address >(32, true);
}
+ static address set_handler(CodeBuffer* buffer)
+ {
+ address handler = _handler;
+ int size = buffer->code_size();
+ if (handler + size > _handler_blob->instructions_end()) {
+ // get a new handler blob
+ handler = set_handler_blob();
+ }
+ memcpy(handler, buffer->code_begin(), size);
+ ICache::invalidate_range(handler, size);
+ _handler = handler + size;
+ return handler;
+ }
+
public:
static void add(methodHandle method)
{
@@ -315,16 +350,17 @@
// create handler if necessary
if (index < 0) {
ResourceMark rm;
- CodeBuffer* buffer = new CodeBuffer(_buffer,
- SignatureHandlerLibrary::size);
+ ptrdiff_t align_offset = (address)
+ round_to((intptr_t) _buffer, CodeEntryAlignment) -
+ (address)_buffer;
+ CodeBuffer* buffer = new CodeBuffer((address)
+ (_buffer + align_offset),
+ SignatureHandlerLibrary::size -
+ align_offset);
InterpreterRuntime::SignatureHandlerGenerator(method, buffer).generate(fingerprint);
- // copy into C-heap allocated memory location
- address handler = (address)NEW_C_HEAP_ARRAY(u_char, buffer->code_size());
- memcpy(handler, buffer->code_begin(), buffer->code_size());
- ICache::invalidate_range(handler, buffer->code_size());
+ // copy into code heap
+ address handler = set_handler(buffer);
// debugging suppport
if (PrintSignatureHandlers) {
tty->cr();
@@ -188,9 +226,11 @@
};
+BufferBlob* SignatureHandlerLibrary::_handler_blob = NULL;
+address SignatureHandlerLibrary::_handler = NULL;
GrowableArray<uint64_t>* SignatureHandlerLibrary::_fingerprints = NULL;
GrowableArray<address >* SignatureHandlerLibrary::_handlers = NULL;
-uint64_t SignatureHandlerLibrary::_buffer[SignatureHandlerLibrary::size/sizeof(uint64_t)+1]; // the temporary code buffer
+uchar SignatureHandlerLibrary::_buffer[SignatureHandlerLibrary::size]; // the temporary code buffer
IRT_ENTRY(void, InterpreterRuntime::prepare_native_call(JavaThread* thread, methodOop method))