Visual Studio - Projekt Speicherbereiche / -größe festlegen

thTwentY

Cadet 3rd Year
Registriert
Feb. 2008
Beiträge
56
Hallo Zusammen,

ich arbeite gerade an einem Projekt und teste gerade eine eigens implementierte Datenstruktur in C. Bei jeder neuen Debugsession werden die Speicherbereiche für Variablen etc. neu vergeben und das nervt gewaltig.

1. Durchlauf
Variable X hat die Adresse 0x0097bed4

2. Durchlauf
Variable X hat die Adresse 0x00ff3af10

...

Weiß jemand von euch ob Visual Studio eine Funktion oder Tool bereitstellt, um diese Speicherbereiche für ein Projekt festlegen und fixieren zu können? Muss man das dem OS iwie beibringen, dass das Programm dieses Speicherlayout verwenden soll?

z.B.
.data = 0x000 - 0x1FF
.heap = 0x200 - 0x3FF
.stack = 0x400 - 0x5FF


Vielleicht weiß jemand was und kann mir helfen 🙂
Danke und schöne Grüße
 
Ist ein Feature und kein Bug (Stichwort ALSR). Es gibt in diesem Thread noch ein bisschen mehr Infos dazu die evtl. helfen koennen einen Workaround einzurichten.
 
  • Gefällt mir
Reaktionen: thTwentY, nutrix, andy_0 und 2 andere
Ich bin kein super erfahrener Programmierer aber benutzt man dafür nicht Pointer?
 
  • Gefällt mir
Reaktionen: andy_m4
Selbst bei fixem Layout werden die konkreten Adressen wegen ASLR unterschiedlich sein zwischen Programmläufen. Es gibt hier z.B. Informationen um das zu deaktivieren aber sollte man sich genau überlegen, ob man das machen möchte. Und auch das wird noch nicht alle Probleme lösen.

Bist du dir sicher, dass das Memory Layout dein Problem ist? Solltest du nicht beschreiben was dir beim Debuggen Probleme bereitet und fragen, wie man das besser lösen kann? Die Frage hier klingt nach typischen XY-Problem.
 
  • Gefällt mir
Reaktionen: thTwentY, BeBur, andy_m4 und 2 andere
thTwentY schrieb:
ich arbeite gerade an einem Projekt und teste gerade eine eigens implementierte Datenstruktur in C. Bei jeder neuen Debugsession werden die Speicherbereiche für Variablen etc. neu vergeben und das nervt gewaltig.
Das ist vollkommen normal und auch in Ordnung so. Speicher wird immer dynamisch bereitgestellt, und das kannst Du so auch gar nicht beeinflußen. Wie willst Du denn bitte kontrollieren, wer wann was wo wie im RAM an Ressourcen bereitsstellt?
Ergänzung ()

FreshLemon schrieb:
Ich bin kein super erfahrener Programmierer aber benutzt man dafür nicht Pointer?
Ja, aber das hilft Dir doch nicht beim Debuggen, wenn Speicherbereiche angesprochen werden.
Ergänzung ()

schneup schrieb:
Ist ein Feature und kein Bug (Stichwort ALSR).
Das ist aber nur die "halbe" Wahrheit. Fakt ist, daß Speicher wie RAM und Dateisysteme schon immer, seit den Anfängen der IT, dynamisch sind.
 
  • Gefällt mir
Reaktionen: aragorn92 und andy_m4
nutrix schrieb:
Das ist aber nur die "halbe" Wahrheit. Fakt ist, daß Speicher wie RAM und Dateisysteme schon immer, seit den Anfängen der IT, dynamisch sind.
Bis auf den Stack kamen mir Speicherbereiche bei Heimcomputern wie dem C64 immer recht statisch vor. Oder was meinst Du genau mit diesem Satz?
 
Am besten du beschreibst mal was das konkrete Problem ist. Vermutlich kann man das was du willst auch anders bzw. besser lösen.
 
FreshLemon schrieb:
benutzt man dafür nicht Pointer?
Und Pointeroffsets.
thTwentY schrieb:
1. Durchlauf
Variable X hat die Adresse 0x0097bed4

2. Durchlauf
Variable X hat die Adresse 0x00ff3af10
D.h. man schaut beim Debuggen auf Variable X, sowie auf den Speicherbereich (&X +1), (&X+2), (&X+beliebigesOffset)

Diese Ausdrücke (Offsets auf eine Adresse / einen Pointer) kann man ja einfach als Expressions im Debugger eintragen.

Oder ich habe die Frage auch ganz falsch verstanden.
 
  • Gefällt mir
Reaktionen: BeBur
Ich habe letztens sogar auf den Speicher an sich drauf geschaut aus irgendeinem Grund. Ging glaube ich um eine zur Laufzeit geladenen DLL. Wobei die Symbole dazu eigentlich vorhanden waren... ging vermutlich einfacher schneller.

Aber TE muss nochmal mehr schreiben, sonst kann man nicht helfen.
 
Ist ein Feature und kein Bug (Stichwort ALSR). Es gibt in diesem Thread noch ein bisschen mehr Infos dazu die evtl. helfen koennen einen Workaround einzurichten.
Habe ich auch nicht behauptet.
Ich such ja nur nach einer Lösung wich ich das beim testen abschalten kann.
Ergänzung ()

Selbst bei fixem Layout werden die konkreten Adressen wegen ASLR unterschiedlich sein zwischen Programmläufen. Es gibt hier z.B. Informationen um das zu deaktivieren aber sollte man sich genau überlegen, ob man das machen möchte. Und auch das wird noch nicht alle Probleme lösen.
Den Vorschlag sieht hilfreich aus und wird bei Gelegenheit getestet.
Ergänzung ()

Das ist vollkommen normal und auch in Ordnung so. Speicher wird immer dynamisch bereitgestellt, und das kannst Du so auch gar nicht beeinflußen. Wie willst Du denn bitte kontrollieren, wer wann was wo wie im RAM an Ressourcen bereitsstellt?
Ich weiß - ich will beim testen auch nur einen konsisten statischen Startzustand herstellen 🙂
Ergänzung ()

Am besten du beschreibst mal was das konkrete Problem ist. Vermutlich kann man das was du willst auch anders bzw. besser lösen.
Ich habe z.B. folgende Lookup-Table - so wie ich es im Moment auch aufwendig praktiziere:
0x0097bed4 -> main();
0x00989911 -> printf();

Wenn ich nun bei jedem neuen Debugdurchlauf andere Adressen für die beiden Funktionen erhalte, muss ich ständig meine Lookup-Table (und auch die im Hirn 😆) neu generieren. Wenn man ein paar Durchläufe gemacht hat, weiß man auch welche Adresse wo hingehört aber nicht wenn dynamisch etwas neues zugewiesen wird.

Und da ich faul bin - such ich nach Wegen die mir das Leben einfacher machen 😉
Ergänzung ()

Oder ich habe die Frage auch ganz falsch verstanden.
Also mit Pointer und Offsets hat es weniger zutun, sondern wie ich mir beim testen eine Umgebung schaffen kann die immer gleich ist.
 
Zuletzt bearbeitet:
Das mit der Lookuptable klingt schräg. Was ist der Datentyp der Werte? Ist das der Funktionsname als Zeichenkette?

Da du Eingangs ja von debuggen sprichst - du versuchst gerade aber nicht nur einfach den Funktionsnamen auszugeben, oder sowas? Dafür hats Compiler Intrinsics wie func.

Oder bin ich einfach zu unkreativ, um mir vorstellen zu können, wofür du so eine Lookuptable brauchst mit Funktionsadressen und Funktionsnamen?
 
thTwentY schrieb:
muss ich ständig meine Lookup-Table (und auch die im Hirn 😆) neu generieren.
Was machst du denn mit den Lookup-Tabellen? Normalerweise braucht man sowas nicht, daher die ganzen Nachfragen. Auch die Offsets werden unterschiedlich sein, je nachdem welche stdlib du verwendest, welchen Compiler oder in welcher Version oder mit welchen Flags.
 
In der Applikation gibt es keine Lookup-Table - die erstelle ich mir außerhalb (extern) in einer Textdatei extra fürs debuggen und ordne eine Adresse einem Element zu.

Nehmen wir als Beispiel eine verkette Liste. Ein Zeiger zeigt auf das erste Element und das widerum auf das zweite Element und das widerum auf das dritte Element, usw bis zum Ende:

Zeiger -> 0x110FF90 -> 0x110FF91 -> 0x110F92 -> 0

Da die Datenstruktur für die Verwaltung einer verketteten Liste sehr einfach gehalten ist, gibts auch nicht viel zu sehen:
struct List{ struct List* next; };

So und wer weiß z.B. bei hundert Einträgen noch was das Element mit der Adresse 0x11FF91 beinhaltet (welche Funktion, welche Variablen, ... ) - steckt hinter einer Adresse überhaupt ein Listenelement oder ist mir ein Fehler irgendwo unterlaufen und es ist eine Funktionsadresse ... und da kommt meine externe Lookup-Table ins Spiel 😉

Wenn ich Jetzt durch den Programmcode debugge und es wird eine Adresse als Parameter einer Funktion übergeben - kann ich in meiner externen Lookup-Table nachschauen was hinter der Adresse steckt. Ist es eine Funktion, eine stinknormale Variable, ein Listenelement, ... usw.
 
Zuletzt bearbeitet:
Wie hast du das denn implementiert? Üblicherweise haben die Zeiger einen bestimmten Typ (z.B Listelement) und Visual Studio zeigt dir dann an was an der Adresse gespeichert ist auf die der Zeiger zeigt. Auch wenn das aus irgendeinem Grund alles void* Pointer sind kannst du dir das in VS entsprechend des Typs anzeigen lassen. Also die Lookup-Tabelle die du dir baust, die stellt die VS sowieso schon bereit.

Gib doch mal ein wenig Beispielcode.
 
Also bei mir zeigt Visual Studio für einen void* nur eine Adresse an - kann ja auch nicht mehr anzeigen, ist ja ein void*. Für ein spezifisches Objekt wie z.B. das genannte "Listenelement" ist das natürlich anders und die Informationen was sich darin befinden können aufgeschlüsselt und angezeigt werden.

Um das ganze zu verdeutlichen nehmen wir eine generische Struktur "List" von oben und geben Ihr noch eine Funktion mit. Die Funktion fügt neue Elemente in die Liste ein.

C:
struct List
{
    struct List* Next;
}

static inline void list_add( struct List** p_list, struct List* p_item )
{
    // do something useful ...
}

Irgendwo in meinem Programm habe ich jetzt einen konkreten Typ "ListUint32t" und diese Liste verwaltet nun Elemente vom Typ "uint32_t". Es könnte auch eine Liste sein die "float"s verwaltet - was der Anwendungsfall halt hergibt und ich brauche.

C:
struct ListUint32t
{
    struct ListUint32t* Next;
    uint32_t Value;
}

Damit ich nun nicht für jeden Typ eine Funktion schreiben muss, die eine Element hinzufügt - gibt es die generische Variante oben. Das ganze geht in die Richtung von "Templates", wie man es von C++ kennt.

Wenn ich nun folgenden Beispielcode schreibe

C:
struct ListUint32t* list_uint32t = 0;

struct ListUint32t list_uint32t_item1 = { .Next = 0, .Value = 1 };
struct ListUint32t list_uint32t_item2 = { .Next = 0, .Value = 2 };

list_add( &list_uint32t, &list_uint32t_item1 );
list_add( &list_uint32t, &list_uint32t_item2 );

sehe ich beim debuggen in der Funktion "list_add" nicht was das genau für ein Objekt ist und daher die Lookup-Table.
Ergänzung ()

@schneup
@Chuuei
Danke euch beiden 👍 ASLR war die richtige Richtung.

Hab mir die Links einmal angeschaut und fand es sehr interessant. Auch die Linkeroption hat mir für die "Debug" Konfiguration das Leben ein bisschen einfacher gemacht und ist nun deaktiviert!
 
Zuletzt bearbeitet:
Okay, ich sehe ein, dass bei einer dynamisch allokierten verketteten Liste die nötigen Expressions im Debugger kompliziert werden. Ich dachte da nämlich an sowas (insbesondere die letzten beiden Zeilen):
expressions.png

Aber 100 mal hintereinander .Next schreiben bringt auch keine Übersicht. Bei einem Array aus deinem Struct wäre es sehr übersichtlich darstellbar.
Und wahrscheinlich ist es auch wenig zielführend, zu Debugzwecken immer einen include einzufügen, der dir deine Liste in ein übersichtliches Array packt (so etwa:
debug_items_aliases.png

items.png

- obwohl, man könnte mit vielleicht Makros arbeiten, damit könnte man evtl. die Übersichtlichkeit im Debugger behalten.)
 
An sich keine schlechte Idee mit der Liste ABER ich verwalte in meiner Liste nicht nur einen Typ sondern mehrere unterschiedliche Typen und das zielt auf Vererbung ab d.h. eine Basisstruktur mit mehreren abgeleiteten Strukturen 😆

Also nach meiner Erfahrung wirds mit Makros noch schlimmer. Hab mal zum Spaß eine Funktion als Makro geschrieben und das hat der Debugger gekonnt ignoriert bzw. übersprungen 🙂
 
Zurück
Oben