PDA

View Full Version : [C - C++] Controllo 32-64 bit.


stohuman
11-01-2013, 18:51
E' fattibile in C o C++ scrivere un programma che determini se il sistema sia a 32 o 64 bit (e magari l'architettura completa del processore) in modo automatico...?

Esempio banale..
Eseguibile compilato x86 32bit.. (per piu piattaforme possibili)
if (...funzione controllo...== 32)
{
manda in esecuzione codice compilato per 32bit...
}
else if (...funzione controllo...==64)
{
manda in esecuzione codice compilato per 64 bit...
}
else
il sistema non è supportato...

Possibilmente indipendente dal sistema operativo su cui si lavora, quindi senza chiamate ma controllando direttamente l'hw.
Anche in C-ASM se solo in C o C++ non è una cosa possibile.

cdimauro
11-01-2013, 20:50
E' possibile sia a compile-time che a run-time.

A run-time è semplice: dovrebbe bastare controllare la dimensione dei puntatori.

A compile-time non è facile, perché dipende dal compilatore e della piattaforma, e quindi dai simboli che vengono esposti. Per cui devi implementare i classici controlli #if/ifdef.

stohuman
12-01-2013, 02:10
Si credo di aver afferrato abbastanza il concetto, i puntatori li sto studiando da un po ma non mi entrano bene.. le direttive le avevo viste giusto ieri :D

Proverò con le direttive del compilatore Dev.

Al massimo due cavolate che mi sono venute in mente..
fare il controllo sizeof(int), anche se significa tirarsi la zappa in bocca, e da li capire.. magari piu tardi faccio delle prove dato che ho un Vista 32bit e 7 64bit, vedo cosa salta fuori.
Seconda cavolata potrebbe essere sempre un eseguibile x86 che fa partire prima un programma a 64 bit che nel caso non funzioni ritorni un valore e faccia partire quello a 32 bit..

Go to test!

cdimauro
12-01-2013, 08:16
Ti sconsiglio di usare il sizeof applicato a int o long. Gli int generalmente rimangono a 32 bit, mentre per i long alcuni compilatori (ABI, in realtà) li definiscono a 32 bit, e altri a 64 bit. Quindi sono inaffidabili per il problema che vuoi risolvere.

I puntatori sono ABBASTANZA (lo sottolineo, perché NON è detto che sia vero, ma non voglio dilungarmi in discorsi più complicati) affidabili da questo punto di vista, ed è quello a cui dovresti dedicarti.

AnonimoVeneziano
12-01-2013, 11:07
Misurare la dimensione dei puntatori come ha detto cdimauro sembra la soluzione migliore (sempre tenendo in mente che non è generalmente portabile, perché di archittetture strane a questo mondo ce ne sono tante , ma se si sta su x86 o ARM non ci sono problemi).

Volevo però specificare che quella soluzione è praticamente già compile-time , perchè codice come questo:



void func() {
if (sizeof(void*) == 8)
// Fai roba
else if (sizeof(void*) == 4)
// Fai altra roba
else
assert(0);
}



di fatto dal 99.9% dei compilatori C/C++ viene compilato senza branch considerando che sizeof è una espressione costante a compile-time.

Quindi cercarne altre più compilcate a compile-time non ha senso.

Ciao

stohuman
12-01-2013, 17:52
Forse è meglio se mi ristudio tutte le architetture meglio... sono tante e troppe.
Grazie per il vostro tempo! :D

tomminno
13-01-2013, 13:46
Se il software è compilato a 32 bit il sizeof(void*) sarà sempre pari a 4, indipendentemente dalla versione del sistema su cui sta girando il software... :banned:

A compile time l'unica informazione che è possibile ottenere è se si sta compilando il programma a 32 o 64 bit ;)

A runtime non esiste un modo multipiattaforma per stabilire se il sistema è a 32 o 64bit: su linux ci sono mille mila comandi che forniscono l'informazione, uno dei tanti è "getconf LONG_BIT" che restituisce 32 o 64, su Windows generalmente si cerca se esiste un metodo presente solo a 64bit ad esempio se kernel32.dll espone l'API IsWow64Process il sistema è a 64bit.

Per l'architettura del processore la cosa è più standard, su linux al solito basta parsare /proc/cpuinfo, su Windows basta chiamare GetSystemInfo

Vincenzo1968
13-01-2013, 13:57
Se il software è compilato a 32 bit il sizeof(void*) sarà sempre pari a 4, indipendentemente dalla versione del sistema su cui sta girando il software... :banned:

A compile time l'unica informazione che è possibile ottenere è se si sta compilando il programma a 32 o 64 bit ;)

A runtime non esiste un modo multipiattaforma per stabilire se il sistema è a 32 o 64bit: su linux ci sono mille mila comandi che forniscono l'informazione, uno dei tanti è "getconf LONG_BIT" che restituisce 32 o 64, su Windows generalmente si cerca se esiste un metodo presente solo a 64bit ad esempio se kernel32.dll espone l'API IsWow64Process il sistema è a 64bit.

Per l'architettura del processore la cosa è più standard, su linux al solito basta parsare /proc/cpuinfo, su Windows basta chiamare GetSystemInfo

Su Windows una soluzione accettabile potrebbe essere quella proposta da stohuman?


Seconda cavolata potrebbe essere sempre un eseguibile x86 che fa partire prima un programma a 64 bit che nel caso non funzioni ritorni un valore e faccia partire quello a 32 bit..


L'unica camurrìa è che, tentando di eseguire l'applicazione a 64 bit su un sistema a 32, ti spunta la messagebox di errore. Bisognerebbe eseguire il processo in background tramite CreateProcess senza fare spuntare la message box.

Debbo provare.

Vincenzo1968
13-01-2013, 14:05
Oppure si potrebbe aprire una delle dll nella cartella di sistema ed esaminare l'header per vedere se sono a 32 o 64 bit.

Dove le trovo le specifiche dei file per Windows?

cdimauro
13-01-2013, 14:08
Se il software è compilato a 32 bit il sizeof(void*) sarà sempre pari a 4, indipendentemente dalla versione del sistema su cui sta girando il software... :banned:
Potrebbe anche essere 6. :fiufiu:

cdimauro
13-01-2013, 14:09
Oppure si potrebbe aprire una delle dll nella cartella di sistema ed esaminare l'header per vedere se sono a 32 o 64 bit.

Dove le trovo le specifiche dei file per Windows?
http://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx
http://msdn.microsoft.com/en-us/library/ms809762.aspx

Vincenzo1968
13-01-2013, 14:21
Grazie :)

Nel frattempo avevo trovato anche questi:

http://msdn.microsoft.com/en-us/windows/hardware/gg463119.aspx

http://msdn.microsoft.com/en-us/library/ms809762.aspx

;)

EDIT: Ah no, il secondo link è quello tuo ;)

Vincenzo1968
13-01-2013, 14:30
A questo punto, avendo le specifiche, faccio un programmino e lo posto.
Apro due o tre dll nella cartella di sistema, leggo gli header, e vedo se il formato è PE(32 bit) o PE32+(64 bit).

cdimauro
13-01-2013, 14:57
Per un mio progetto ho usato questo (http://code.google.com/p/distorm/downloads/list), che era già pronto (dislib.py).

C'è anche tanto C, se dovesse servirti. :D

Vincenzo1968
13-01-2013, 15:01
Voglio provare a farlo da me, c'è più soddisfazione. :D

http://img15.imageshack.us/img15/6666/90960184.jpg

http://www.hwupgrade.org/public/style_emoticons/default/coolface.png

Vincenzo1968
13-01-2013, 15:11
http://img40.imageshack.us/img40/7853/pe2j.jpg

http://www.hwupgrade.org/public/style_emoticons/default/coolface.png

cdimauro
13-01-2013, 15:12
E pensare che c'è gente che è convinta che Microsoft abbia un piano diabolico per supportare soltanto gli x86 di Intel. :O

Vincenzo1968
13-01-2013, 15:16
A runtime non esiste un modo multipiattaforma per stabilire se il sistema è a 32 o 64bit: su linux ci sono mille mila comandi che forniscono l'informazione, uno dei tanti è "getconf LONG_BIT" che restituisce 32 o 64, su Windows generalmente si cerca se esiste un metodo presente solo a 64bit ad esempio se kernel32.dll espone l'API IsWow64Process il sistema è a 64bit.

Per l'architettura del processore la cosa è più standard, su linux al solito basta parsare /proc/cpuinfo, su Windows basta chiamare GetSystemInfo

Per la fretta m'era sfuggita questa parte. Allora non c'è bisogno di leggere gli header della dll.
Comunque il programmino lo faccio lo stesso(così, for the lulz) :D

Vincenzo1968
13-01-2013, 15:36
http://img692.imageshack.us/img692/646/pe3u.jpg

http://www.hwupgrade.org/public/style_emoticons/default/coolface.png

Vincenzo1968
13-01-2013, 15:52
Per Ruby si può usare pedump:

Installazione:

gem install pedump


;)

tomminno
13-01-2013, 15:54
Potrebbe anche essere 6. :fiufiu:

Si beh nel contesto Windows, Linux, Osx è 4.

stohuman
13-01-2013, 17:35
Avrei voluto partecipare piu attivamente alla discussione ma stavo dormendo ._.

Comunque...
L'unica camurrìa è che, tentando di eseguire l'applicazione a 64 bit su un sistema a 32, ti spunta la messagebox di errore. Bisognerebbe eseguire il processo in background tramite CreateProcess senza fare spuntare la message box.

Debbo provare.

Hai capito quello che ho detto o_o, oddio.
Si una cosa del genere se si lavora sotto windows, o linux anche se non so come funzioni li.

Il BIOS quando controlla l'hardware non è che ne controlla anche le specifiche?

Vincenzo1968
13-01-2013, 19:03
Si può fare così:


#include <windows.h>
#include <tchar.h>
#include <stdio.h>

int main()
{
SYSTEM_INFO siSysInfo;

GetSystemInfo(&siSysInfo);

if ( siSysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||
siSysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 )
{
wprintf(TEXT("Questo sistema e' a 64 bit."));
}
else if ( siSysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL )
{
wprintf(TEXT("Questo sistema e' a 32 bit."));
}
else
{
wprintf(TEXT("Questo sistema non si sa che e'."));
}


getc(stdin);

return 0;
}


Da me, con Windows XP a 32 bit, il programma stampa correttamente "Questo sistema è a 32 bit."

Debbo provarlo sul portatile con Windows 8 a 32 bit e nell'altro computer con Windows 8 a 64 bit.

Qualcuno potrebbe cortesemente provarlo su Windows 7 e/o Vista? Thanks.

EDIT: Non funziona! Anche su Windows 8 a 64 bit mi stampa "Questo è un sistema a 32 bit.". Mah!

Vincenzo1968
13-01-2013, 20:07
Se invece uso la funzione GetNativeSystemInfo, funziona:

Su questa macchina(Windows 8 a 64 bit; processore a 64 bit):
http://img545.imageshack.us/img545/5976/macchinanuova.jpg

Il risultato è:
http://img827.imageshack.us/img827/2231/whatarch.jpg



Mentre su quest'altra macchina(Windows XP a 32 bit; processore a 64 bit):
http://img7.imageshack.us/img7/5461/macchinae.jpg

Il risultato è:
http://img202.imageshack.us/img202/2231/whatarch.jpg


#include <windows.h>
#include <tchar.h>
#include <stdio.h>

int main()
{
SYSTEM_INFO siSysInfo;

GetNativeSystemInfo(&siSysInfo);

if ( siSysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||
siSysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 )
{
wprintf(TEXT("\nQuesto sistema e' a 64 bit. Ciao.\n"));
}
else if ( siSysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL )
{
wprintf(TEXT("\nQuesto sistema e' a 32 bit. Ciao Ciao.\n"));
}
else
{
wprintf(TEXT("\nQuesto sistema non si sa che e'. Addio.\n"));
}

wprintf(TEXT("\nHardware information: \n"));
wprintf(TEXT(" OEM ID: %u\n"), siSysInfo.dwOemId);
wprintf(TEXT(" Number of processors: %u\n"), siSysInfo.dwNumberOfProcessors);
wprintf(TEXT(" Page size: %u\n"), siSysInfo.dwPageSize);
wprintf(TEXT(" Processor type: %u\n"), siSysInfo.dwProcessorType);
wprintf(TEXT(" Minimum application address: %lx\n"), siSysInfo.lpMinimumApplicationAddress);
wprintf(TEXT(" Maximum application address: %lx\n"), siSysInfo.lpMaximumApplicationAddress);
wprintf(TEXT(" Active processor mask: %u\n"), siSysInfo.dwActiveProcessorMask);

if ( siSysInfo.dwProcessorType == PROCESSOR_INTEL_IA64 ||
siSysInfo.dwProcessorType == PROCESSOR_AMD_X8664 )
{
wprintf(TEXT("\nQuesto sistema e' a 64 bit.\n"));
}
else
{
wprintf(TEXT("\nQuesto sistema e' a 32 bit.\n"));
}

getc(stdin);

return 0;
}

marco.r
13-01-2013, 20:20
E' fattibile in C o C++ scrivere un programma che determini se il sistema sia a 32 o 64 bit (e magari l'architettura completa del processore) in modo automatico...?

Esempio banale..
Eseguibile compilato x86 32bit.. (per piu piattaforme possibili)
if (...funzione controllo...== 32)
{
manda in esecuzione codice compilato per 32bit...
}
else if (...funzione controllo...==64)
{
manda in esecuzione codice compilato per 64 bit...
}
else
il sistema non è supportato...

Possibilmente indipendente dal sistema operativo su cui si lavora, quindi senza chiamate ma controllando direttamente l'hw.
Anche in C-ASM se solo in C o C++ non è una cosa possibile.

Dipende da cosa intendi con "codice compilato per 64 bit"... non tutti i sistemi a 64 bit sono uguali, idem per quelli a 32 bit, per cui devi discriminare in base alle caratteristiche che ti interessano.
Ad esempio se controlli la dimensione del puntatore sai se puoi utilizzare puntatori a 32 o 64 bit, ma non se sei su una architettura a 64 (ci sono ABI per processori a 64 bit che usano 32 bit, vedi ad esempio http://en.wikipedia.org/wiki/X32_ABI ).
se vuoi sapere se sono disponibili alcune caratteristiche del processore (e.g. SSE) non so se ci sia un modo portabile.

stohuman
13-01-2013, 20:27
Lo testo io su windows 7 64 bit, solo un attimo che devo installare Visual Studio :D

Vincenzo1968
13-01-2013, 20:31
Lo testo io su windows 7 64 bit, solo un attimo che devo installare Visual Studio :D

Se vuoi ti posso dare l'eseguibile(a 32 bit) che ho creato io.

EDIT: Eccolo: http://www.filedropper.com/whatarch

stohuman
13-01-2013, 20:33
Dipende da cosa intendi con "codice compilato per 64 bit"... non tutti i sistemi a 64 bit sono uguali, idem per quelli a 32 bit, per cui devi discriminare in base alle caratteristiche che ti interessano.
Ad esempio se controlli la dimensione del puntatore sai se puoi utilizzare puntatori a 32 o 64 bit, ma non se sei su una architettura a 64 (ci sono ABI per processori a 64 bit che usano 32 bit, vedi ad esempio http://en.wikipedia.org/wiki/X32_ABI ).
se vuoi sapere se sono disponibili alcune caratteristiche del processore (e.g. SSE) non so se ci sia un modo portabile.

Si effettivamente hai ragione, io conto piu sul fatto che venga usato su processori con architetture x86, quindi la maggior parte di intel e amd.
Quello che ho pensato inizialmente e escluso è scrivere un eseguibile che controlla l'architettura completa della cpu in modo da essere sicuri cosa sia.. ma questo è fuori dal limite da quanto ho capito.

Vincenzo1968
13-01-2013, 20:36
Vado a provarlo nel portatilino con Windows 8 a 32 bit.

stohuman
13-01-2013, 20:39
Se vuoi ti posso dare l'eseguibile(a 32 bit) che ho creato io.

EDIT: Eccolo: http://www.filedropper.com/whatarch

Thanks :D
Come da programma:
http://oi48.tinypic.com/14l62vb.jpg
Si effettivamente questo puo funzionare.

cdimauro
13-01-2013, 20:40
(ci sono ABI per processori a 64 bit che usano 32 bit, vedi ad esempio http://en.wikipedia.org/wiki/X32_ABI ).
Finalmente l'hanno resa pubblica. Bene. :D

Vincenzo1968
13-01-2013, 20:46
Anche nel portatilino con Windows 8 a 32 bit(e processore a 64 bit) funziona:

http://img138.imageshack.us/img138/9601/whatarchport.jpg

:yeah: :winner: :yeah:

Vincenzo1968
13-01-2013, 20:48
Ora bisognerebbe provarlo su Windows 7 a 32 bit e su Vista(32/64).

Chi si offre?

AnonimoVeneziano
13-01-2013, 20:53
Dipende da cosa intendi con "codice compilato per 64 bit"... non tutti i sistemi a 64 bit sono uguali, idem per quelli a 32 bit, per cui devi discriminare in base alle caratteristiche che ti interessano.
Ad esempio se controlli la dimensione del puntatore sai se puoi utilizzare puntatori a 32 o 64 bit, ma non se sei su una architettura a 64 (ci sono ABI per processori a 64 bit che usano 32 bit, vedi ad esempio http://en.wikipedia.org/wiki/X32_ABI ).
se vuoi sapere se sono disponibili alcune caratteristiche del processore (e.g. SSE) non so se ci sia un modo portabile.

Assolutamente vero, mi ero dimenticato della ABI x32.

stohuman
13-01-2013, 20:59
Ora bisognerebbe provarlo su Windows 7 a 32 bit e su Vista(32/64).

Chi si offre?

Vista con le unità removibili è un cancaro.
http://oi46.tinypic.com/33pgiug.jpg

Modifica: ops mi sono dimenticato di nascondere il nome del vaio :S

Vincenzo1968
13-01-2013, 21:07
Funziona alla grande!

:yeah: :winner: :yeah:

:D

stohuman
13-01-2013, 21:18
Funziona alla grande!

:yeah: :winner: :yeah:

:D

Monster!

tomminno
14-01-2013, 10:49
Grandi!
Avete trovato l'API giusta. Ovunque nei forum si trova che per il detect del sistema bisogna vedere le funzioni implementate... :muro:

stohuman
15-01-2013, 08:29
Posto per vincenzo dato che è stato bloccato :(

Un paio di modifiche.

#include <windows.h>
#include <tchar.h>
#include <stdio.h>

int main()
{
SYSTEM_INFO siSysInfo;

GetNativeSystemInfo(&siSysInfo);

if ( siSysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||
siSysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 )
{
_tprintf(TEXT("\nQuesto sistema e' a 64 bit. Ciao.\n"));
}
else if ( siSysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL )
{
_tprintf(TEXT("\nQuesto sistema e' a 32 bit. Ciao Ciao.\n"));
}
else
{
_tprintf(TEXT("\nQuesto sistema non si sa che e'. Addio.\n"));
}

_tprintf(TEXT("\nHardware information: \n"));
_tprintf(TEXT(" OEM ID: %u\n"), siSysInfo.dwOemId);
_tprintf(TEXT(" Number of processors: %u\n"), siSysInfo.dwNumberOfProcessors);
_tprintf(TEXT(" Page size: %u\n"), siSysInfo.dwPageSize);
_tprintf(TEXT(" Processor type: %u\n"), siSysInfo.dwProcessorType);
_tprintf(TEXT(" Minimum application address: %lx\n"), siSysInfo.lpMinimumApplicationAddress);
_tprintf(TEXT(" Maximum application address: %lx\n"), siSysInfo.lpMaximumApplicationAddress);
_tprintf(TEXT(" Active processor mask: %u\n"), siSysInfo.dwActiveProcessorMask);

if ( siSysInfo.dwProcessorType == PROCESSOR_INTEL_IA64 ||
siSysInfo.dwProcessorType == PROCESSOR_AMD_X8664 )
{
_tprintf(TEXT("\nQuesto sistema e' a 64 bit.\n"));
}
else
{
_tprintf(TEXT("\nQuesto sistema e' a 32 bit.\n"));
}

getc(stdin);

return 0;
}

Sempre vincenzo:
ho sostituito wprintf con _tprintf in modo da poter compilare in modalità unicode e non.
_tprintf è una macro definita in tchar.h che si espande in wprintf se unicode è definito. Se non è definito si espande in printf.

Vincenzo1968
17-01-2013, 10:36
Il merito va a Tomminno che ha suggerito l'api GetSystemInfo. Se non funziona non è certo colpa sua ma della Microsoft(e sono in molti a lamentarsi di questa cosa qui nel blog MSDN).

Senza il suo suggerimento non ci sarei arrivato all'api GetNativeSystemInfo o ci sarei arrivato con molta più fatica e perdita di tempo(e bestemmioni).

;)