News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

GAS and DLL's please help ...

Started by James Ladd, May 26, 2006, 08:34:37 AM

Previous topic - Next topic

James Ladd

I have a simple main prog and Im trying to build and link to a dynamic library
using the Gnu Assembler. However, it's not working. Below is what im getting.

$ make
ld -shared libsimple.o -o libsimple.so
ld -L . -e_start -o simple simple.o -lsimple kernel32
ld: cannot find -lsimple
make: *** [simple] Error 1


I am using cygwin under windows XP but I dont think this is the issue as I
can make the main prog without error if im not linking to the library.

Can someone help me with this ?
I'm just trying to get a simple main prog call a function that does nothing but
'ret' inside a DLL/so.

Whilst im on windows I have kept the names as they would appear under
linux. I hope this doesnt confuse the issue.
I'm also calling the source that makes the simple.so/dll 'libsimple'.

My source is below.

Rgs, James.

Makefile

SRC =   simple.s libsimple.s

OBJ =   simple.o libsimple.o

BIN =   simple libsimple

LIBS =  simple kernel32

all: $(OBJ) $(BIN)

clean:
        rm -f $(OBJ)
        rm -f $(BIN)
        rm -f *.so

.s.o:
        as -g -o $@ $<

simple: simple.o libsimple
        ld -L . -e_start -o simple simple.o -l$(LIBS)

libsimple: libsimple.o
        ld -shared libsimple.o -o libsimple.so


simple.s

.intel_syntax noprefix

.arch pentium

.global _start

.data
    .extern _ExitProcess@4
    .extern _myfunc

.text

.align 8
_start:

    xor eax, eax

    call _myfunc

    pushd 0
    call _ExitProcess@4



libsimple.s

.intel_syntax noprefix

.arch pentium

.data

.text

myfunc:

    xor eax, eax
    ret


hutch--

james,

At the minimum a DLL must have an entry point which is in the form or a LibMain or DllMain. It assumes 3 x 4 bytes are passed on the stack, it must return NON zero in EAX to start and it must balance the stack for the 12 bytes. This should be the first proc in the code.

To build it specifically as a DLL, you must use a linker that does this as it is not performed by the assembler. If you are using LD.EXE you will have to have a wade through the command line options and there are a lot of them. LD --help
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

MichaelW

LD apparently has a chicken/egg problem in creating a DLL. Using the information here:

http://programming.ccp14.ac.uk/cygnus-gnu-win32/misc/gnu-win32/dll-hints.txt

I was finally able to create the app and the DLL without the tools returning an error, and once I changed _myfunc to return non-zero, the app ran without apparent error (even though balancing the stack did not occur to me).

Apparantly attachments are not working yet.

test.asm

.intel_syntax noprefix
.arch pentium
.global _start
.extern _ExitProcess@4
.extern _myfunc
.data
.text
.align 8
_start:
    xor eax, eax
    call _myfunc
    pushd 0
    call _ExitProcess@4


testdll.asm

.intel_syntax noprefix
.arch pentium
.global _myfunc
.data
.text
_myfunc:
    ;xor eax, eax
    mov eax, 1
    ret


testdll.dll.def

LIBRARY testdll.dll
EXPORTS
myfunc


makeit.bat

as -o testdll.o testdll.asm

pause

ld --dll -e _myfunc -o jnk --base-file testdll.base testdll.o

pause

dlltool --dllname testdll.dll --base-file testdll.base --def testdll.dll.def --output-lib testdll.dll.a --output-exp testdll.exp

pause

ld --dll -e _myfunc -o testdll.dll testdll.o testdll.exp testdll.base

pause

as -o test.o test.asm

pause

ld -e _start -subsystem console -L C:\masm32\lib -o test.exe test.o testdll.dll.a --library=kernel32

pause

eschew obfuscation

James Ladd

Thanks Hutch and Michael,

I can't believe I forgot LibMain.
I was so busy yesterday with painting a house and moving that I really didnt concentrate.

I'll apply the items here and let you know how I go.
It's 8am and we have a house inspection soon so I have to try this in between cleaning
and moving.

Michael I have tried the process you have outlined and it works without error.
However, when debugging (with DDD) I get a segmentation fault :(

Im also thinking that you had to change myfunc to return non-zero because
as Hutch suggests there needs to be a DllMain and you set the entry point for the
Dll to be _myfunc.

I'll make these changes and see how I go.

Thanks again.

Rgs, James.

James Ladd

Hutch - Balance the stack ?

Quote
At the minimum a DLL must have an entry point which is in the form or a LibMain or DllMain. It assumes 3 x 4 bytes are passed on the stack, it must return NON zero in EAX to start and it must balance the stack for the 12 bytes. This should be the first proc in the code.

Is this what you mean ?


_DllMain:
    mov eax, 1
    add esp, 12
    ret


hutch--

James,

Must be the first code in the app.

LibMain:
mov eax, 1
ret 12

All of the rest of your code here.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

James Ladd

Hutch - You so totally rock !!
That fixed my code right up. 

This is what I have now for GAS and it builds a simple file and loads a DLL and calls a function in it.
The function doesnt do much because I just want it to be called and return.

The environment I am using is cygwin under windows XP.
This allows me to use the Gnu Toolchain (Gnu Assembler, ld, objdump, ddd, etc)
and to have my code compile under both windows and linux (it will very soon at least).

Makefile

OBJS =  libsimple.o

all: libsimple simple

clean:
        rm -f $(OBJS) *.dll *.base *.exp *.temp *.a *.lib *.def

.s.o:
        as -g -o $@ $<

libsimple: $(OBJS)

        ld --dll -e _DllMain -o $@.temp --base-file $@.base $(OBJS)

        ar rc $@.a $(OBJS)
        @echo LIBRARY $@ > $@.def
        @echo EXPORTS >> $@.def
        nm $@.a | grep [TC] | sed '/ _/s//  /' | awk '{print $$3;}' >> $@.def

        dlltool --dllname $@.dll -b $@.base --def $@.def -l $@.lib -e $@.exp

        ld --dll -e _DllMain -o $@.dll $(OBJS) $@.exp

simple: simple.o

        ld -e _start -subsystem console -o $@.exe $@.o libsimple.lib --library kernel32

This Makefile creates simple.exe and libsimple.lib and libsimple.dll
It also makes the .DEF file automatically.

libsimple.s

.intel_syntax noprefix

.arch pentium

.global _DllMain
.global _myfunc

.data

.text

_DllMain:
    mov eax, 1
    ret 12

_myfunc:
    xor eax, eax
    ret

This is the DLL code which doesnt do much other than export _myfunc which
as you can see, does nothing but return.

simple.s

.intel_syntax noprefix

.arch pentium

.global _start

.data
.extern _ExitProcess@4
.extern _myfunc

.text

.align 8
_start:

    xor eax, eax
    call _myfunc

    pushd 0
    call _ExitProcess@4

This is the simple.exe source and it just calls myfunc and thats it.

In linux source files for assembler have a '.s' extension.
My next task will be to make this work under Linux as well as Windows
from the one piece of source. So watch out for some 'ifeq' stuff in
the Makefile

Im currently using 'ddd' to debug the code. THis is a GUI front end to gdb that works
under X-windows. So the same toolchain is being used on both platforms.

All comments welcomed.

Special thanks to Hutch and MichaelW !!!

Rgs, James.

Vortex

Here is a small example coded with MinGW. It displays a message box on the screen.

testdll.asm :

.intel_syntax noprefix

.global _DllMain
.global _MsgBox

.data
.extern _MessageBoxA@16
caption:
.asciz  "Hello!"

.text

_DllMain:

    mov     eax,1
    ret     12

_MsgBox:

    push    ebp
    mov     ebp,esp
    pushd   0
    push    OFFSET caption
    push    DWORD PTR [ebp+8]
    pushd   0
    call    _MessageBoxA@16
    leave
    ret     4


demo.asm :

.intel_syntax noprefix
.global _start

.data
.extern _ExitProcess@4
.extern _MsgBox
msg:
.asciz "It's a GAS dll"

.text

_start:

    push    OFFSET msg
    call    _MsgBox
    pushd   0
    call    _ExitProcess@4


The switch -s is used to strip the symbols to reduce the size of the DLL and EXE

Build.bat :

@echo Build DLL

\mingw\bin\as -o testdll.o testdll.asm
\mingw\bin\ld --dll -L C:\masm32\lib -e _DllMain -o jnk --base-file testdll.base  testdll.o --library=user32 -s
\mingw\bin\dlltool --dllname testdll.dll --base-file testdll.base --def testdll.dll.def --output-lib testdll.dll.a --output-exp testdll.exp
\mingw\bin\ld --dll -L C:\masm32\lib -e _DllMain -o testdll.dll testdll.o testdll.exp --base-file testdll.base  --library=user32 -s

@echo Build EXE

\mingw\bin\as -o demo.o demo.asm
\mingw\bin\ld -e _start -subsystem windows -L C:\masm32\lib -o demo.exe demo.o testdll.dll.a --library=kernel32 -s

[attachment deleted by admin]

Vortex

This time, I used Polink to link the object files making the building process more easy :

@echo Build DLL

\mingw\bin\as -o testdll.o testdll.asm
\pellesc\bin\polink /SUBSYSTEM:WINDOWS /DLL /DEF:testdll.dll.def /ENTRY:DllMain testdll.o \pellesc\lib\win\user32.lib
@echo Build EXE

\mingw\bin\as -o demo.o demo.asm
\pellesc\bin\polink /SUBSYSTEM:WINDOWS /ENTRY:start demo.o testdll.lib \pellesc\lib\win\kernel32.lib


test.dll.def modified like the following :

LIBRARY testdll
EXPORTS
_MsgBox

[attachment deleted by admin]

James Ladd

Vortex,

Thanks for your example.
Do you recommend using the -s and does it work if you have -g (debug) set?

Rgs, James.

Vortex

I never tried the -g debug switch so I cannot tell anything about the effects of -s combined with -g

In my modest opinion, I recommend using the -s switch reducing the size of the final EXE \ DLL

James Ladd

Vortex, Thanks.
The -g switch will generate debug info, so it wont be hard for me to test this
in combination with -s.

James Ladd


Vortex

Building decorated import library with ld.exe :

\mingw\bin\dlltool -d test.def -l testdll.a

test.def :

LIBRARY testdll.dll
EXPORTS
MsgBox@4=MsgBox

[attachment deleted by admin]