Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

undefined reference to `gai_strerrorA' #10

Closed
sgeto opened this issue Aug 31, 2017 · 23 comments
Closed

undefined reference to `gai_strerrorA' #10

sgeto opened this issue Aug 31, 2017 · 23 comments

Comments

@sgeto
Copy link
Contributor

sgeto commented Aug 31, 2017

In the file ec_socket.c on line 90 there is a call to gai_strerror() that wsock_trace (unlike winsock) seems unable to handle.

I'm only able to test this with mingw (gcc 7.2).

@sgeto
Copy link
Contributor Author

sgeto commented Aug 31, 2017

I just realized that my MinGW distro (Msys2) does not define __MINGW64_VERSION_MAJOR

I think that's the problem. I guess yours does...

@sgeto
Copy link
Contributor Author

sgeto commented Aug 31, 2017

another update:
__MINGW64_VERSION_MAJOR is defined in _mingw_mac.h and is included with any of these:

wincrypt.h
windows.h
winnt.h        
winsvc.h       
winuser.h      
winver.h       
ws2def.h       
_bsd_types.h

@gvanem
Copy link
Owner

gvanem commented Aug 31, 2017

unable to handle.

You mean unable to trace? That's probably because gai_strerrorA() is inlined in your <ws2tcpip.h>.

If your MinGW defines __MINGW64_VERSION_MAJOR, it should surely do it in every file. Try with:

#include <stdio.h>
int main (void)
{
#ifdef __MINGW64_VERSION_MAJOR
  printf ("MinGW: %d.%d\n", __MINGW64_VERSION_MAJOR, __MINGW64_VERSION_MINOR);
#endif
  return (0);
}

@sgeto
Copy link
Contributor Author

sgeto commented Aug 31, 2017

You mean unable to trace?

I wish. I'm not getting it to link.
I even removed the conditionals around them in wsock_trace.c such as in this one:

#if defined(__MINGW32__) && defined(__MINGW64_VERSION_MAJOR)
  DEF_FUNC (char *,    gai_strerrorA, (int err));
  DEF_FUNC (wchar_t *, gai_strerrorW, (int err));
#endif

but gai_strerrorA still doesn't show up in the def file. it is being skipped somehow.

Tring your snippet correctly output __MINGW64_VERSION_MAJOR:

$ gcc -o mingw.exe mingw.c
$ ./mingw
MinGW: 5.0
$

@sgeto
Copy link
Contributor Author

sgeto commented Aug 31, 2017

Ok I think I found something:
defining USE_DEF_FILE exports gai_strerrorA().
This also takes care of the linking error.
However, setting USE_DEF_FILE to 1 in Makefile.MingW isn't currently possible.

@gvanem
Copy link
Owner

gvanem commented Aug 31, 2017

I don't understand the above. USE_DEF_FILE=1 doesn't work for my MinGW (TDM-gcc). And pedump wsock_trace_mw.dll shows gai_strerror* is not exported. Which suites me fine.

And in MS-SDK 8.1+, they are also inlined (using FormatMessage()) since they are really not part of Winsock2. They are not even part of mswsock.dll.

So I'm not sure what the problem or the fix is...

@gvanem
Copy link
Owner

gvanem commented Aug 31, 2017

Also, check your libws2_32.a for the presence of gai_strerror*. Use e.g.:

nm <MinGW-root>\lib\libws2_32.a | grep ' T gai'

or (grep ' T _gai).

If they're not there, it would mean they are inlined (and no need to be there. But that maybe depends on gcc -O0).

If they are there, libwsock_trace.a should also have them (to be a replacement for libws2_32.a).

So again, I'm not sure what the suite-all-MinGW-fix is.

@sgeto
Copy link
Contributor Author

sgeto commented Aug 31, 2017

I can't perform these check right now but to clarify a few things:

  • It's true, by default wsock_trace doesn't export gai_strerror*.
    This was never an issue for me as I never needed it.
    I think in order to understand whether this is an issue (or whether wsock_trace should export it) you need to create a similar condition as in example file (ec_socket.c) compile and link it and see...
    If linking fails only with wsock_trace, but not with ws2_32, then I guess this is an issue.

  • these lines in Makefile.MingW make it currently not possible to set USE_DEF_FILE to 1:

ifeq ($(USE_DEF_FILE),1)
  DEF_FILE    = wsock_trace$(X_SUFFIX).def
  WSOCK_DEPS += $(DEF_FILE)
endif

removing these should define USE_DEF_FILE on the command line which leads to gai_strerror* being exported and this fixes my compile error. Of course, one could also just add -DUSE_DEF_FILE to CFLAGS instead.

@gvanem
Copy link
Owner

gvanem commented Aug 31, 2017

.. to create a similar condition as in example file (ec_socket.c) compile and link it and see...

I have done that with success (using clang-cl and TDM-gcc/MinGW) But that is because I've used another MinGW that you use. Since there is so many MinGW-distros to chose from, I've not tried yours. Msys2 was it? Give me an URL or a download and I could try it.

The USE_DEF_FILE=1 for MinGW used to work, but not any longer. So I'd probably remove it since it's rather confusing.

@sgeto
Copy link
Contributor Author

sgeto commented Aug 31, 2017

Not sure if you can say the same, but I find Mingw usually behaving much better when I use the *nix approach of exporting functions and creating shared objects instead of MS's __declspec keywords.
It has proven to be useful to me when debugging or porting things. One of the few reasons I think Mingw is here to stay.
I'm just saying this because I feel that (part of) the USE_DEF_FILE feature should stay. Under another name maybe and only for Mingw/cygwin. This part in common.h really helped to make sense of this issue I'm facing and could act a "fallback solution":

#if defined(USE_DEF_FILE)
  #define EXPORT
#else
  #define EXPORT  __declspec(dllexport)
#endif

Maybe I can make something less confusing out of it if you're cool with that. Would be quite educating as well.

Anyways, Msys2 is a very actively maintained Mingw distro. It's actually a cygwin port that comes with native Mingw distros.
You can get it from here:
http://www.msys2.org
Quick guide:

  1. get the x64 installer (if your PC supports it)
  2. follow initial install instruction 1-7 on above page
  3. Then, open a Mingw32 or Mingw64 shell. Ignore the Msys shell (it's cygwin)
  4. They use a port of arch linux's package manager Pacman for downloading and updating stuff. So to install a mingw toolchain (from the Mingw32 or Mingw64 shell) do:
    pacman -S base-devel mingw-w64-i686-toolchain mingw-w64-x86_64-toolchain

The way geoip.exe is executed in Makefile.MingW (without preceding it with a slash-dot), you are expecting it to be executed from cmd rather than bash (which requires a slash-dot). This could be handle like so geoip.exe -4g geoip-gen4.c || ./geoip.exe -4g geoip-gen4.c
but that's for another issue :-D

@sgeto
Copy link
Contributor Author

sgeto commented Sep 1, 2017

gai_strerror* is present in Msys's libws2_32.a

$ nm /mingw64/x86_64-w64-mingw32/lib/libws2_32.a | grep ' T gai'
0000000000000000 T gai_strerrorA
0000000000000000 T gai_strerrorW

@gvanem
Copy link
Owner

gvanem commented Sep 1, 2017

Okay, I'll try to built ettercap again with TDM-gcc + libwsock_trace.a again.

@gvanem
Copy link
Owner

gvanem commented Sep 1, 2017

I studied the man-page of ld a bit. I found that adding -Wl,--wrap=gai_strerrorA,--wrap=gai_strerrorW can be a fix while linking an application using libwsock_trace.a.

And then in wsock_trace.c, add these wrappers:

#if defined(__MINGW32__) 
char __declspec(dllexport) *__wrap_gai_strerrorA (int err)
{
  char *rc = win_strerror ((DWORD)err);

  WSTRACE ("gai_strerrorA (%d) -> %s", err, rc);
  return (rc);
}

wchar_t __declspec(dllexport) *__wrap_gai_strerrorW (int err)
{
  static wchar_t err_buf [300];
  char          *err_str = win_strerror ((DWORD)err);

  err_buf[0] = '\0';
  MultiByteToWideChar (CP_ACP, 0, err_str, -1, err_buf, DIM(err_buf));
  WSTRACE ("gai_strerrorW (%d) -> %" WCHAR_FMT, err, err_buf);
  return (err_buf);
}
#endif  /* __MINGW32__ && __MINGW64_VERSION_MAJOR */

Please try it.

@gvanem
Copy link
Owner

gvanem commented Sep 1, 2017

Another fix would be to create a new gai_strerror.c with no <ws2tcpip.h> included and add it after the link-stage (as is done for data.o):

	ar rs libwsock_trace.a $(DATA_OBJ) gai_strerror.o

Thus removing the gai_strerror*() from wsock_trace.c. Not sure what's best.

@sgeto
Copy link
Contributor Author

sgeto commented Sep 1, 2017

Just as an aside. I wanted to see where the tendency is in the various mingw distros with respect the presents of gai_strerror*() in libws2_32.a
They appear to be also present in old-school mingw32 (MinGW-w64). Here is the output from my Debian box:

➜  ~ nm /usr/x86_64-w64-mingw32/lib/libws2_32.a | grep ' T gai' 
0000000000000000 T gai_strerrorA                                
0000000000000000 T gai_strerrorW                                
➜  ~ nm /usr/i686-w64-mingw32/lib/libws2_32.a | grep ' T gai'   
➜  ~ nm /usr/i686-w64-mingw32/lib/libws2_32.a | grep ' T _gai'  
00000000 T _gai_strerrorA                                       
00000000 T _gai_strerrorW                                       
➜  ~  

This is the default mingw32 cross distro found in Debian, Ubuntu and co.

@sgeto
Copy link
Contributor Author

sgeto commented Sep 1, 2017

I'll try the wrapper. Looks fancy...

Okay, I'll try to built ettercap again with TDM-gcc + libwsock_trace.a again.

A debug build. Since the call only happens there...

@sgeto
Copy link
Contributor Author

sgeto commented Sep 2, 2017

Using the wrapper workaround, gai_strerrorA and gai_strerrorW are now exported as __wrap_gai_strerrorA and __wrap_gai_strerrorW respectively.
This unfortunately still breaks linking. I guess the linker expects their actual names.
Am I doing it right?

@gvanem
Copy link
Owner

gvanem commented Sep 2, 2017

Did you add -Wl,--wrap=gai_strerrorA,--wrap=gai_strerrorW to the link-command?
And what's the link-error? Anyway, I'll do this differently.

@sgeto
Copy link
Contributor Author

sgeto commented Sep 2, 2017

Did you add -Wl,--wrap=gai_strerrorA,--wrap=gai_strerrorW to the link-command?

Yes, I did.
Are you going with your second approach? How would a local gai_strerror.c look like?

@sgeto
Copy link
Contributor Author

sgeto commented Sep 2, 2017

link error:

MakeFiles/lib_ettercap.dir/objects.a(ec_socket.c.obj): In function `open_socket':
make[1]: *** [CMakeFiles/Makefile2:256: src/CMakeFiles/lib_ettercap.dir/all] Error 2
C:/Users/Ali/projects/ettercap-master/src/ec_socket.c:89: undefined reference to `gai_strerrorA'
C:/Users/Ali/projects/ettercap-master/src/ec_socket.c:89: undefined reference to `gai_strerrorA'
collect2.exe: error: ld returned 1 exit status
make[2]: *** [src/CMakeFiles/lib_ettercap.dir/build.make:3434: src/libettercap.dll] Error 1

@gvanem
Copy link
Owner

gvanem commented Sep 2, 2017

Try with this commit: 418408b.

But some problems in AppVeyor's MinGW:
https://ci.appveyor.com/project/gvanem/wsock-trace/build/1.0.62/job/3r9qx8gbfqyeoikk

Seems the last commit fixed it in AppVeyor:
https://ci.appveyor.com/project/gvanem/wsock-trace/build/1.0.64

@sgeto
Copy link
Contributor Author

sgeto commented Sep 2, 2017

Yes, that worked. Links in just fine.
Tests are okay too.
Thanks for the effort.

@gvanem
Copy link
Owner

gvanem commented Sep 2, 2017

Assume all is fixed. Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants