Cara, eu já tive que fazer isso em um projeto aonde a aplicação tinha que se comunicar com o modem do cliente. Logo de cara, foram necessario 2 bibliotecas, uma para linux (.SO) e outra para Windows (.DLL).
Para facilitar o trabalho eu fiz o seguinte, criei minha DLL normalmente, então, criei uma outra DLL que funcionava como uma Facade, ou seja, o Java conseguia conversar com ela e ela tinha as chamadas para a DLL.
Vamos por partes, para o Java conseguir chamar a DLL ou SO, ela deve atender algumas especificações, que podem ser obtidas atravez o comando javah. Este comando varre as classes e gera um .h (header do C/C++) com o protótipo das funções que foram marcadas com o modificador “native”.
Com este .h em mãos, coloque na pasta do projeto facade e implemente exatamente os metódos exportados. Adicione a esta DLL a referencia a DLL que vc deseja chamar e coloque as chamadas do Java chamando a DLL alvo.
Para compilar no gcc, tem uma flag -shared, mas só isso não é o suficiente e não recomendo o uso do gcc no windows, já que para usa-lo é necessário instalar ou o cygwin ou o MinGW, ambos com um ou outro probleminha para rodar no windows.