[c++] неразрешенный внешний символ _memset

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by realcoder, 3 Oct 2011.

  1. realcoder

    realcoder Member

    Joined:
    9 Dec 2010
    Messages:
    226
    Likes Received:
    11
    Reputations:
    4
    написал socks5 сервак:
    Code:
    #pragma comment(linker, "/MERGE:.data=.text")
    #pragma comment(linker, "/MERGE:.rdata=.text")
    #pragma comment(linker, "/SECTION:.text,EWR")
    
    #include <WinSock2.h>
    #include <Windows.h>
    
    
    struct auths5{
    	BYTE ver;//версия
    	BYTE nMethods;//кол-во методов
    };
    
    struct auth_resp
    {
    	BYTE ver;//версия
    	BYTE method;//выбранный метод
    };
    
    
    struct s5request{
     BYTE Version; // 5
     BYTE Cmd ; // 1 - CONNECT
     BYTE Reserved; // 0
     BYTE AType; // 1 - IPv4; 3 - domain name; 4 - IPv6
    };
    
    struct resp{
    BYTE Version; // 5
     BYTE Rep ; // 0 - Ok
     BYTE Reserved; // 0
     BYTE AType; // 1 - IPv4; 3 - domain name; 4 - IPv6
    };
    
    void portmapper(SOCKET client,SOCKET target)
    {
    
    	int		len;
    	char	buf[1024];
    	fd_set	fd;
    
    	while(TRUE){
    		FD_ZERO(&fd);
    		FD_SET(client, &fd);
    		FD_SET(target, &fd);
    		for(int i=0;i<1024;i++) buf[i]=0;
    		select(0, &fd, NULL, NULL, NULL);
    		if(FD_ISSET(client, &fd)){//если прислал данные клиент
    			//перешлем от одного другому
    			if((len = recv(client,buf,sizeof(buf),0))== -1){
    				
    				break;
    			}
    			if(send(target,buf,len,0)== -1){
    				break;
    			}
    		}
    	    if(FD_ISSET(target,&fd)){//если прислал данные сервер
    			//перешлем от одного другому
    			if((len = recv(target,buf,sizeof(buf),0))== -1){
    				break;
    			
    			}
    			if(send(client,buf,len,0)== -1){
    				break;
    			}
    		}
    	}
    
    	//чистим за собой
    	closesocket(client);
    	closesocket(target);
    }
    
    DWORD __stdcall ClientRoute(void *params)
    {
    	SOCKET as= *(SOCKET *)params;
    	if(as==INVALID_SOCKET) 
    		return -1;//продолжаем прием если ошибка
    		auths5 req;//структура авторизации
    		recv(as,(char *)&req,sizeof(req),0);//принимаем
    		BYTE *methods=(BYTE *)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,req.nMethods);//инициализируем массив методов авторизации, поддерживаемых клиентом
    		for(int i=0;i<req.nMethods;i++) methods[i]=0;
    		recv(as,(char *)methods,req.nMethods,0);//получаем методы авторизации
    		auth_resp r;//заполняем ответ
    		r.ver=5;//5-я версия
    		r.method=0;//авторизация не нужна
    		send(as,(char *)&r,sizeof(r),0);//посылаем ответ
    		s5request s5r;//запрос
    		recv(as,(char *)&s5r,sizeof(s5r),0);//получаем запрос
    		//printf("ver: %d, cmd: %d,reserved: %d,atype: %d\n",s5r.Version,s5r.Cmd,s5r.Reserved,s5r.AType);//выводим полученный запрос
    		if(s5r.Cmd==1)//если команда connect
    		{
    			if(s5r.AType==1)//если IpV4
    			{
    				DWORD addr=0;//адрес
    				recv(as,(char *)&addr,sizeof(DWORD),0);
    				WORD port=0;//порт
    				recv(as,(char *)&port,sizeof(WORD),0);
    				sockaddr_in caddr;//заполняем адресную структуру
    				caddr.sin_addr.S_un.S_addr=addr;
    				caddr.sin_family=AF_INET;
    				caddr.sin_port=port;
    				SOCKET ss=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//создание сокета
    				if(connect(ss,(sockaddr *)&caddr,sizeof(caddr))==0)//коннектимся
    				{
    				resp rsp;
    				rsp.AType=1;
    				rsp.Rep=0;//успешно
    				rsp.Reserved=0;
    				rsp.Version=5;
    				send(as,(char *)&rsp,sizeof(rsp),0);//заголовок
    				send(as,(char *)&caddr.sin_addr.S_un.S_addr,sizeof(DWORD),0);//адрес
    				send(as,(char *)&caddr.sin_port,sizeof(WORD),0);//порт
    				portmapper(as,ss);//зарускаем обмен данными
    				}
    			}
    
    			if(s5r.AType==3)//если доменное имя
    			{
    			BYTE alen=0;
    			recv(as,(char *)&alen,sizeof(BYTE),0);//получаем длину доменного имени
    			char *domain=(char *)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,alen);//выделяем память нужного размера
    			domain[alen]='\0';
    			recv(as,domain,alen,0);//получаем доменное имя
    			WORD aport=0;//порт
    			recv(as,(char *)&aport,sizeof(WORD),0);
    			hostent *hst=gethostbyname(domain);
    			char *addr=inet_ntoa(*(in_addr *)(*(hst->h_addr_list)));
    			sockaddr_in caddr;//заполняем адресную структуру
    				caddr.sin_addr.S_un.S_addr=inet_addr(addr);
    				caddr.sin_family=AF_INET;
    				caddr.sin_port=aport;
    				SOCKET ss=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//создание сокета
    				if(connect(ss,(sockaddr *)&caddr,sizeof(caddr))==0)//коннектимся
    				{
    				resp rsp;
    				rsp.AType=1;
    				rsp.Rep=0;//успешно
    				rsp.Reserved=0;
    				rsp.Version=5;
    				send(as,(char *)&rsp,sizeof(rsp),0);//заголовок
    				send(as,(char *)&caddr.sin_addr.S_un.S_addr,sizeof(DWORD),0);//адрес
    				send(as,(char *)&caddr.sin_port,sizeof(WORD),0);//порт
    				portmapper(as,ss);//зарускаем обмен данными
    				}
    
    			}
    
    		}
    	return 0;
    }
    
    DWORD __stdcall socks5_listen(LPVOID param)
    {
    	SOCKET s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//создаем сокет
    	if(s==INVALID_SOCKET) return -1;//если не создался сокет  выходим
    	//заполняем адресную структуру
    	sockaddr_in sa;
    	sa.sin_addr.S_un.S_addr=INADDR_ANY;
    	sa.sin_port=htons(1080);
    	sa.sin_family=AF_INET;
    	if(bind(s,(sockaddr *)&sa,sizeof(sa))==(-1)) return -1;//выходим если ошибка 
    	
    	if(listen(s,5)==(-1)) return -1;//выходим если ошибка	
    	while(true)//прием соединений
    	{
    		sockaddr_in saa;//адресная структура для принятого соединения
    		SOCKET as=accept(s,(sockaddr *)&saa,NULL);//прием
    		//создаем отдельный поток для каждого соединения
    		DWORD id=0;
    		CreateThread(NULL,0,ClientRoute,&as,0,&id);
    		
    	}
    
    	return 0;
    }
    void entry()//энтрипойнт
    {
    		/*инит сокетов*/
    	WSAData w;
    	if(WSAStartup(MAKEWORD(2,2),&w)!=0) ExitProcess(0);//в случае неудачного инита выходим
    	DWORD dwid;
    	HANDLE hThread=CreateThread(NULL,0,socks5_listen,NULL,0,&dwid);//асинхронно стратуем прослушку
    	WaitForSingleObject(hThread,INFINITE);
    	ExitProcess(0);
    }
    
    
    
    полностью отказался от c crt, но почемуто у меня вылазит ошибка
    Ошибка 3 error LNK2001: неразрешенный внешний символ "_memset" c:\Users\vova\documents\visual studio 2010\Projects\socks5\socks5\socks_serv.obj socks5

    хотя memset там не использую...
     
  2. realcoder

    realcoder Member

    Joined:
    9 Dec 2010
    Messages:
    226
    Likes Received:
    11
    Reputations:
    4
    так все ок когда писал консолку по шаблону. опера и аську пахала просто за*бись. а когда решил перевести на windows и убрать все лишее по статье как писал slesh - вот такая херня
     
  3. GRRRL Power

    GRRRL Power Elder - Старейшина

    Joined:
    13 Jul 2010
    Messages:
    823
    Likes Received:
    185
    Reputations:
    84
    Генерируем ассемблерный листинг, видим, что компилятор использует memset при оптимизации твоего цикла:
    PHP:
    for(int i=0;i<1024;i++) buf[i]=0;
    Берем и оптимизируем его сами:
    PHP:
    for(int i=0;i<1024/4;i++) ((long*)&buf[0])[i]=0;
    memset из листинга исчезает. У меня был еще символ _crt_debugger_hook, от него я избавился, выключив опцию Buffer Security Check в настройках компилятора.

    Код кстати трешовый, Си и Си++ вместе, а еще память освобождать забываешь за собой.
     
  4. roman921

    roman921 Member

    Joined:
    24 May 2015
    Messages:
    316
    Likes Received:
    22
    Reputations:
    0
    А после этого приема компилятор выкидывает предупреждение.
    warning C4789: конечная область для копирования памяти слишком мала
    А как некоторые функции подключить в проект из crt. Я там нашел memset.c, но как правильно ее в проект подключить через инклуды.
     
  5. neviens

    neviens Member

    Joined:
    9 Oct 2013
    Messages:
    82
    Likes Received:
    28
    Reputations:
    3
    Почему, это довольно-таки удобная штука.
    Если мало кода и не нравится, что exe файл большой получается, компилируй с /MD свичом, приложение слинкуется с crt, который в dll'е.

    Err, незаметил дату создания первого поста.
     
  6. Ins3t

    Ins3t Харьковчанин

    Joined:
    18 Jul 2009
    Messages:
    939
    Likes Received:
    429
    Reputations:
    139
    так а толку, все равно редист таскать с собой придется.
     
  7. neviens

    neviens Member

    Joined:
    9 Oct 2013
    Messages:
    82
    Likes Received:
    28
    Reputations:
    3
    Надо линковать с msvcrt.lib из WinDDK, msvcrt.dll есть на каждом Win, от 98 до 10.
    Есть некоторые ограничения (filesize < 2GB, нет C++, нет %lld, %llx), но в большинстве случаев это некритично.
    Кстати MinGW так и делает (линкует с msvcrt.dll), можно на нём собирать а не на MSVC.
     
  8. Ins3t

    Ins3t Харьковчанин

    Joined:
    18 Jul 2009
    Messages:
    939
    Likes Received:
    429
    Reputations:
    139
    ну я хз как нужно писать чтоб хватило одного лишь msvcrt.dll :)
    если пишешь на человеческом С++ то тянутся еще msvcp.dll, vccorlib.dll, vcruntime.dll, а их по дефолту нету.