Related
when i Compile the GTK+ code ( in C ) gcc has many error !
this code is from GTK Demo but it's Examples not work on my Fedore 37 !
Screenshot from GTK Demo
that is source code :
#include <glib/gi18n.h>
#include <gtk/gtk.h>
enum
{
ICON_NAME_COL,
TEXT_COL
};
static GtkTreeModel *
create_icon_store (void)
{
const char *icon_names[6] = {
"dialog-warning",
"process-stop",
"document-new",
"edit-clear",
NULL,
"document-open"
};
const char *labels[6] = {
N_("Warning"),
N_("Stop"),
N_("New"),
N_("Clear"),
NULL,
N_("Open")
};
GtkTreeIter iter;
GtkListStore *store;
int i;
store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
for (i = 0; i < G_N_ELEMENTS (icon_names); i++)
{
if (icon_names[i])
{
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
ICON_NAME_COL, icon_names[i],
TEXT_COL, _(labels[i]),
-1);
}
else
{
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
ICON_NAME_COL, NULL,
TEXT_COL, "separator",
-1);
}
}
return GTK_TREE_MODEL (store);
}
/* A GtkCellLayoutDataFunc that demonstrates how one can control
* sensitivity of rows. This particular function does nothing
* useful and just makes the second row insensitive.
*/
static void
set_sensitive (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
GtkTreeModel *tree_model,
GtkTreeIter *iter,
gpointer data)
{
GtkTreePath *path;
int *indices;
gboolean sensitive;
path = gtk_tree_model_get_path (tree_model, iter);
indices = gtk_tree_path_get_indices (path);
sensitive = indices[0] != 1;
gtk_tree_path_free (path);
g_object_set (cell, "sensitive", sensitive, NULL);
}
/* A GtkTreeViewRowSeparatorFunc that demonstrates how rows can be
* rendered as separators. This particular function does nothing
* useful and just turns the fourth row into a separator.
*/
static gboolean
is_separator (GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{
GtkTreePath *path;
gboolean result;
path = gtk_tree_model_get_path (model, iter);
result = gtk_tree_path_get_indices (path)[0] == 4;
gtk_tree_path_free (path);
return result;
}
static GtkTreeModel *
create_capital_store (void)
{
struct {
const char *group;
const char *capital;
} capitals[] = {
{ "A - B", NULL },
{ NULL, "Albany" },
{ NULL, "Annapolis" },
{ NULL, "Atlanta" },
{ NULL, "Augusta" },
{ NULL, "Austin" },
{ NULL, "Baton Rouge" },
{ NULL, "Bismarck" },
{ NULL, "Boise" },
{ NULL, "Boston" },
{ "C - D", NULL },
{ NULL, "Carson City" },
{ NULL, "Charleston" },
{ NULL, "Cheyenne" },
{ NULL, "Columbia" },
{ NULL, "Columbus" },
{ NULL, "Concord" },
{ NULL, "Denver" },
{ NULL, "Des Moines" },
{ NULL, "Dover" },
{ "E - J", NULL },
{ NULL, "Frankfort" },
{ NULL, "Harrisburg" },
{ NULL, "Hartford" },
{ NULL, "Helena" },
{ NULL, "Honolulu" },
{ NULL, "Indianapolis" },
{ NULL, "Jackson" },
{ NULL, "Jefferson City" },
{ NULL, "Juneau" },
{ "K - O", NULL },
{ NULL, "Lansing" },
{ NULL, "Lincoln" },
{ NULL, "Little Rock" },
{ NULL, "Madison" },
{ NULL, "Montgomery" },
{ NULL, "Montpelier" },
{ NULL, "Nashville" },
{ NULL, "Oklahoma City" },
{ NULL, "Olympia" },
{ "P - S", NULL },
{ NULL, "Phoenix" },
{ NULL, "Pierre" },
{ NULL, "Providence" },
{ NULL, "Raleigh" },
{ NULL, "Richmond" },
{ NULL, "Sacramento" },
{ NULL, "Salem" },
{ NULL, "Salt Lake City" },
{ NULL, "Santa Fe" },
{ NULL, "Springfield" },
{ NULL, "St. Paul" },
{ "T - Z", NULL },
{ NULL, "Tallahassee" },
{ NULL, "Topeka" },
{ NULL, "Trenton" },
{ NULL, NULL }
};
GtkTreeIter iter, iter2;
GtkTreeStore *store;
int i;
store = gtk_tree_store_new (1, G_TYPE_STRING);
for (i = 0; capitals[i].group || capitals[i].capital; i++)
{
if (capitals[i].group)
{
gtk_tree_store_append (store, &iter, NULL);
gtk_tree_store_set (store, &iter, 0, capitals[i].group, -1);
}
else if (capitals[i].capital)
{
gtk_tree_store_append (store, &iter2, &iter);
gtk_tree_store_set (store, &iter2, 0, capitals[i].capital, -1);
}
}
return GTK_TREE_MODEL (store);
}
static void
is_capital_sensitive (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
GtkTreeModel *tree_model,
GtkTreeIter *iter,
gpointer data)
{
gboolean sensitive;
sensitive = !gtk_tree_model_iter_has_child (tree_model, iter);
g_object_set (cell, "sensitive", sensitive, NULL);
}
static void
fill_combo_entry (GtkWidget *combo)
{
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "One");
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "Two");
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "2\302\275");
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "Three");
}
/* A simple validating entry */
#define TYPE_MASK_ENTRY (mask_entry_get_type ())
#define MASK_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_MASK_ENTRY, MaskEntry))
#define MASK_ENTRY_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), TYPE_MASK_ENTRY, MaskEntryClass))
#define IS_MASK_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_MASK_ENTRY))
#define IS_MASK_ENTRY_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), TYPE_MASK_ENTRY))
#define MASK_ENTRY_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), TYPE_MASK_ENTRY, MaskEntryClass))
typedef struct _MaskEntry MaskEntry;
struct _MaskEntry
{
GtkEntry entry;
const char *mask;
};
typedef struct _MaskEntryClass MaskEntryClass;
struct _MaskEntryClass
{
GtkEntryClass parent_class;
};
static void mask_entry_editable_init (GtkEditableInterface *iface);
static GType mask_entry_get_type (void);
G_DEFINE_TYPE_WITH_CODE (MaskEntry, mask_entry, GTK_TYPE_ENTRY,
G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE,
mask_entry_editable_init));
static void
mask_entry_set_background (MaskEntry *entry)
{
if (entry->mask)
{
if (!g_regex_match_simple (entry->mask, gtk_editable_get_text (GTK_EDITABLE (entry)), 0, 0))
{
PangoAttrList *attrs;
attrs = pango_attr_list_new ();
pango_attr_list_insert (attrs, pango_attr_foreground_new (65535, 32767, 32767));
gtk_entry_set_attributes (GTK_ENTRY (entry), attrs);
pango_attr_list_unref (attrs);
return;
}
}
gtk_entry_set_attributes (GTK_ENTRY (entry), NULL);
}
static void
mask_entry_changed (GtkEditable *editable)
{
mask_entry_set_background (MASK_ENTRY (editable));
}
static void
mask_entry_init (MaskEntry *entry)
{
entry->mask = NULL;
}
static void
mask_entry_class_init (MaskEntryClass *klass)
{ }
static void
mask_entry_editable_init (GtkEditableInterface *iface)
{
iface->changed = mask_entry_changed;
}
GtkWidget *
do_combobox (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
GtkWidget *vbox, *frame, *box, *combo, *entry;
GtkTreeModel *model;
GtkCellRenderer *renderer;
GtkTreePath *path;
GtkTreeIter iter;
if (!window)
{
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Combo Boxes");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
gtk_widget_set_margin_start (vbox, 10);
gtk_widget_set_margin_end (vbox, 10);
gtk_widget_set_margin_top (vbox, 10);
gtk_widget_set_margin_bottom (vbox, 10);
gtk_window_set_child (GTK_WINDOW (window), vbox);
/* A combobox demonstrating cell renderers, separators and
* insensitive rows
*/
frame = gtk_frame_new ("Items with icons");
gtk_box_append (GTK_BOX (vbox), frame);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_margin_start (box, 5);
gtk_widget_set_margin_end (box, 5);
gtk_widget_set_margin_top (box, 5);
gtk_widget_set_margin_bottom (box, 5);
gtk_frame_set_child (GTK_FRAME (frame), box);
model = create_icon_store ();
combo = gtk_combo_box_new_with_model (model);
g_object_unref (model);
gtk_box_append (GTK_BOX (box), combo);
renderer = gtk_cell_renderer_pixbuf_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, FALSE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
"icon-name", ICON_NAME_COL,
NULL);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo),
renderer,
set_sensitive,
NULL, NULL);
renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
"text", TEXT_COL,
NULL);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo),
renderer,
set_sensitive,
NULL, NULL);
gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo),
is_separator, NULL, NULL);
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
/* A combobox demonstrating trees.
*/
frame = gtk_frame_new ("Where are we ?");
gtk_box_append (GTK_BOX (vbox), frame);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_margin_start (box, 5);
gtk_widget_set_margin_end (box, 5);
gtk_widget_set_margin_top (box, 5);
gtk_widget_set_margin_bottom (box, 5);
gtk_frame_set_child (GTK_FRAME (frame), box);
model = create_capital_store ();
combo = gtk_combo_box_new_with_model (model);
g_object_unref (model);
gtk_box_append (GTK_BOX (box), combo);
renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
"text", 0,
NULL);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo),
renderer,
is_capital_sensitive,
NULL, NULL);
path = gtk_tree_path_new_from_indices (0, 8, -1);
gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_path_free (path);
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &iter);
/* A GtkComboBoxEntry with validation */
frame = gtk_frame_new ("Editable");
gtk_box_append (GTK_BOX (vbox), frame);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_margin_start (box, 5);
gtk_widget_set_margin_end (box, 5);
gtk_widget_set_margin_top (box, 5);
gtk_widget_set_margin_bottom (box, 5);
gtk_frame_set_child (GTK_FRAME (frame), box);
combo = gtk_combo_box_text_new_with_entry ();
fill_combo_entry (combo);
gtk_box_append (GTK_BOX (box), combo);
entry = g_object_new (TYPE_MASK_ENTRY, NULL);
MASK_ENTRY (entry)->mask = "^([0-9]*|One|Two|2\302\275|Three)$";
gtk_combo_box_set_child (GTK_COMBO_BOX (combo), entry);
/* A combobox with string IDs */
frame = gtk_frame_new ("String IDs");
gtk_box_append (GTK_BOX (vbox), frame);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_margin_start (box, 5);
gtk_widget_set_margin_end (box, 5);
gtk_widget_set_margin_top (box, 5);
gtk_widget_set_margin_bottom (box, 5);
gtk_frame_set_child (GTK_FRAME (frame), box);
combo = gtk_combo_box_text_new ();
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "never", "Not visible");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "when-active", "Visible when active");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "always", "Always visible");
gtk_box_append (GTK_BOX (box), combo);
entry = gtk_entry_new ();
g_object_bind_property (combo, "active-id",
entry, "text",
G_BINDING_BIDIRECTIONAL);
gtk_box_append (GTK_BOX (box), entry);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}
but when i Compile it :
gcc `pkg-config --cflags gtk+-3.0` 1.c -o hello `pkg-config --libs gtk+-3.0`
Errors :
1.c: In function ‘mask_entry_set_background’:
1.c:251:47: warning: implicit declaration of function ‘gtk_editable_get_text’; did you mean ‘gtk_editable_get_type’? [-Wimplicit-function-declaration]
251 | if (!g_regex_match_simple (entry->mask, gtk_editable_get_text (GTK_EDITABLE (entry)), 0, 0))
| ^~~~~~~~~~~~~~~~~~~~~
| gtk_editable_get_type
1.c:251:47: warning: passing argument 2 of ‘g_regex_match_simple’ makes pointer from integer without a cast [-Wint-conversion]
251 | if (!g_regex_match_simple (entry->mask, gtk_editable_get_text (GTK_EDITABLE (entry)), 0, 0))
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| |
| int
In file included from /usr/include/glib-2.0/glib.h:77,
from /usr/include/glib-2.0/glib/gi18n.h:23,
from 1.c:1:
/usr/include/glib-2.0/glib/gregex.h:494:71: note: expected ‘const gchar *’ {aka ‘const char *’} but argument is of type ‘int’
494 | const gchar *string,
| ~~~~~~~~~~~~~~~~~~~~~^~~~~~
1.c: In function ‘do_combobox’:
1.c:305:14: error: too few arguments to function ‘gtk_window_new’
305 | window = gtk_window_new ();
| ^~~~~~~~~~~~~~
In file included from /usr/include/gtk-3.0/gtk/gtkdialog.h:32,
from /usr/include/gtk-3.0/gtk/gtkaboutdialog.h:30,
from /usr/include/gtk-3.0/gtk/gtk.h:31,
from 1.c:2:
/usr/include/gtk-3.0/gtk/gtkwindow.h:147:12: note: declared here
147 | GtkWidget* gtk_window_new (GtkWindowType type);
| ^~~~~~~~~~~~~~
1.c:306:5: warning: implicit declaration of function ‘gtk_window_set_display’; did you mean ‘gdk_window_get_display’? [-Wimplicit-function-declaration]
306 | gtk_window_set_display (GTK_WINDOW (window),
| ^~~~~~~~~~~~~~~~~~~~~~
| gdk_window_get_display
1.c:316:5: warning: implicit declaration of function ‘gtk_window_set_child’; did you mean ‘gtk_window_set_role’? [-Wimplicit-function-declaration]
316 | gtk_window_set_child (GTK_WINDOW (window), vbox);
| ^~~~~~~~~~~~~~~~~~~~
| gtk_window_set_role
1.c:322:5: warning: implicit declaration of function ‘gtk_box_append’; did you mean ‘gtk_box_pack_end’? [-Wimplicit-function-declaration]
322 | gtk_box_append (GTK_BOX (vbox), frame);
| ^~~~~~~~~~~~~~
| gtk_box_pack_end
1.c:329:5: warning: implicit declaration of function ‘gtk_frame_set_child’; did you mean ‘gtk_frame_set_label’? [-Wimplicit-function-declaration]
329 | gtk_frame_set_child (GTK_FRAME (frame), box);
| ^~~~~~~~~~~~~~~~~~~
| gtk_frame_set_label
1.c:413:5: warning: implicit declaration of function ‘gtk_combo_box_set_child’; did you mean ‘gtk_combo_box_set_active’? [-Wimplicit-function-declaration]
413 | gtk_combo_box_set_child (GTK_COMBO_BOX (combo), entry);
| ^~~~~~~~~~~~~~~~~~~~~~~
| gtk_combo_box_set_active
1.c:442:5: warning: implicit declaration of function ‘gtk_window_destroy’; did you mean ‘gdk_window_destroy’? [-Wimplicit-function-declaration]
442 | gtk_window_destroy (GTK_WINDOW (window));
| ^~~~~~~~~~~~~~~~~~
| gdk_window_destroy
but when i Click on Run Button on GTK Demo, it run in my computer:
Run Key
Combo Boxes
Is there a problem with the gtk demo ?
Thanks
I tried to compile this code with GCC
and i tried Search on Google
The example code you're looking at and copying is for GTK4 while you're compiling against GTK3
Use
gcc `pkg-config --cflags gtk4` 1.c -o hello `pkg-config --libs gtk4`
I constantly get this error, no matter what I'm doing... I have an ILI9488 with 4-wire SPI and a GT911 capacitive Touch driver on an ESP32 (2MB, no PSRAM, arduino core).
this is my main.ino-file:
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <Wire.h>
#include "Goodix.h"
#define INT_PIN 26
#define RST_PIN 15
#define SDA_PIN 22
#define SCL_PIN 16
Goodix touch = Goodix();
#define DISPLAY_BUF_SIZE 480 * 10
static uint16_t display_widht = 480;
static uint16_t display_height = 320;
TFT_eSPI tft = TFT_eSPI(); /* TFT instance */
bool touched = false;
GTPoint touchDat;
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[ DISPLAY_BUF_SIZE];
lv_disp_drv_t disp_drv; //display driver
lv_indev_drv_t touch_drv; //touchpad driver
void my_disp_flush( lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p ){
uint32_t w = ( area->x2 - area->x1 + 1 );
uint32_t h = ( area->y2 - area->y1 + 1 );
tft.startWrite();
tft.setAddrWindow( area->x1, area->y1, w, h );
tft.pushColors( ( uint16_t * )&color_p->full, w * h, true );
tft.endWrite();
lv_disp_flush_ready( disp );
}
void handleTouch(int8_t contacts, GTPoint* points) {
Serial.printf("Contacts: %d\n", contacts);
if(contacts > 0) touched = true;
else touched = false;
for (uint8_t i = 0; i < contacts; i++) {
touchDat = points[0];
Serial.printf("C%d: %d %d \n", points[i].trackId, points[i].x, points[i].y);
}
}
/*Read the touchpad*/
void my_touchpad_read( lv_indev_drv_t * touch_drv, lv_indev_data_t * data ){
if( !touched ) //kein Touch
{
data->state = LV_INDEV_STATE_REL;
}
else //touch!
{
data->state = LV_INDEV_STATE_PR;
/*Set the coordinates*/
data->point.x = touchDat.x;
data->point.y = touchDat.y;
}
}
void i2cInit(){
Wire.setPins(SDA_PIN, SCL_PIN);
Wire.setClock(400000);
Wire.begin();
delay(100);
}
void touchInit() {
touch.setHandler(handleTouch);
touch.setRes(display_widht, display_height);
touch.setRotation(3);
touch.begin(INT_PIN, RST_PIN, GOODIX_I2C_ADDR_28);
Serial.print("Check ACK on addr request on 0x");
Serial.print(touch.i2cAddr, HEX);
Wire.beginTransmission(touch.i2cAddr);
if (!Wire.endTransmission()) {
Serial.println(": SUCCESS");
} else {
Serial.print(": ERROR!");
}
}
void tftInit(){
tft.begin();
tft.setRotation(3);
lv_disp_draw_buf_init( &draw_buf, buf, NULL, DISPLAY_BUF_SIZE ); //init draw Buffer
/*Initialize the display*/
static lv_disp_drv_t disp_drv;
lv_disp_drv_init( &disp_drv );
/*Change the following line to your display resolution*/
disp_drv.hor_res = display_widht;
disp_drv.ver_res = display_height;
disp_drv.flush_cb = my_disp_flush;
disp_drv.draw_buf = &draw_buf;
lv_disp_drv_register( &disp_drv );
/*Initialize the input device driver*/
static lv_indev_drv_t touch_drv;
lv_indev_drv_init( &touch_drv );
touch_drv.type = LV_INDEV_TYPE_POINTER;
touch_drv.read_cb = my_touchpad_read;
lv_indev_drv_register( &touch_drv );
//create simple label
lv_obj_t *label = lv_label_create( lv_scr_act() );
lv_label_set_text( label, "Hello World!!" );
lv_obj_align( label, LV_ALIGN_CENTER, 0, 0 );
}
void setup() {
Serial.begin(115200); /* prepare for possible serial debug */
i2cInit();
touchInit(); //initialize touch
lv_init();
}
void loop() {
touch.loop();
lv_task_handler(); /* let the GUI do its work */
delay(5);
}
these are my main.ino and lv_config.h-files:
https://gist.github.com/kokospalme/a65448c1d10704066b9c6d2350c84a6d
even if I change LV_MEM_SIZE to something small like 1 or 10, I get the error, that " region `dram0_0_seg' overflowed by 22272 bytes". What am I doing wrong?
I need to get the following information for all of the physical disks in the system when Windows 10 storage spaces is enabled.
Model
Serial Number
Firmware Version
Capacity
Index of the Disk
Pnp Id of the disk (to get the SCSI controller name using CM_Get_Parent)
Location information (Bus number, Target Id and LUN)
What I have tried so far:
Used WMI class MSFT_PhysicalDisk
Although this class gives me the adapter number (so i can do without the disk PNP), the location information it gives is not complete when a disk is connected to a different PCI storage controller (such as the Marvell 92xx SATA 6g controller).
Used SetupDiGetClassDevs with GUID_DEVINTERFACE_DISK, passed the handle to SetupDiGetDeviceInterface and used SetupDiGetDeviceInterfaceDetail for location information (Bus/Target Id/LUN), PNP Id, and Device Path. I can pass the device path to CreateFile and get the rest of the information (similar to this approach). The problem with this is that it does not give me all the physical disks. The disks under the storage spaces pool are omitted.
Use an approach similar to the second one but instead of SetupDiGetDeviceInterface and SetupDiGetDeviceInterfaceDetail, use SetupDiEnumDeviceInfo and CM_Get_DevNode_Registry_Property (using the Disk Drives Guid from here). Although this gives me the location and PNP id for all of the physical disks, I can't use anything here (that I know of) to call CreateFile and get the rest of the details.
How can I get the above details for each of the physical disks when storage spaces is enabled?
As a side note, if there is a way to get the disk PNP id from the disk index using the CreateFile and DeviceIoControl, that can also be very helpful for me.
at first we need enumerate all disks in system by call CM_Get_Device_Interface_ListW and CM_Get_Device_Interface_List_SizeW with GUID_DEVINTERFACE_DISK
#include <Shlwapi.h>
#include <cfgmgr32.h>
#undef _NTDDSTOR_H_
#include <ntddstor.h>
#include <ntdddisk.h>
static volatile UCHAR guz;
CONFIGRET EnumDisks(PCSTR prefix, PGUID InterfaceClassGuid)
{
CONFIGRET err;
PVOID stack = alloca(guz);
ULONG BufferLen = 0, NeedLen = 256;
union {
PVOID buf;
PWSTR pszDeviceInterface;
};
for(;;)
{
if (BufferLen < NeedLen)
{
BufferLen = RtlPointerToOffset(buf = alloca((NeedLen - BufferLen) * sizeof(WCHAR)), stack) / sizeof(WCHAR);
}
switch (err = CM_Get_Device_Interface_ListW(InterfaceClassGuid,
0, pszDeviceInterface, BufferLen, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
case CR_BUFFER_SMALL:
if (err = CM_Get_Device_Interface_List_SizeW(&NeedLen, InterfaceClassGuid,
0, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
default:
return err;
}
continue;
case CR_SUCCESS:
while (*pszDeviceInterface)
{
DbgPrint("Interface=[%S]\n", pszDeviceInterface);
HANDLE hFile = CreateFileW(pszDeviceInterface, FILE_GENERIC_READ,
FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
GetDiskPropertyByHandle(hFile);
CloseHandle(hFile);
}
GetPropertyByInterface(prefix, pszDeviceInterface);
pszDeviceInterface += 1 + wcslen(pszDeviceInterface);
}
return CR_SUCCESS;
}
}
}
CONFIGRET EnumDisks()
{
char prefix[256];
memset(prefix, '\t', sizeof(prefix));
prefix[sizeof(prefix) - 1] = 0;
prefix[0] = 0;
return EnumDisks(prefix + sizeof(prefix) - 1, const_cast<PGUID>(&GUID_DEVINTERFACE_DISK));
}
CM_Get_Device_Interface_ListW return multiple, NULL-terminated Unicode strings, each representing the symbolic link name of an interface instance.
from one side this symbolic link name can be passed to CreateFileW for open disk device. after this we can set some ioctl to disk - for get
Index of the Disk
Capacity
Serial Number
Partition Information
example:
void GetDiskPropertyByHandle(HANDLE hDisk)
{
HANDLE hPartition;
IO_STATUS_BLOCK iosb;
STORAGE_DEVICE_NUMBER sdn;
GET_LENGTH_INFORMATION li;
NTSTATUS status = NtDeviceIoControlFile(hDisk, 0, 0, 0, &iosb,
IOCTL_STORAGE_GET_DEVICE_NUMBER, 0, 0, &sdn, sizeof(sdn));
if (0 <= status && sdn.DeviceType == FILE_DEVICE_DISK && !sdn.PartitionNumber)
{
DbgPrint("\\Device\\Harddisk%d\n", sdn.DeviceNumber);
WCHAR sz[64], *c = sz + swprintf(sz, L"\\Device\\Harddisk%d\\Partition", sdn.DeviceNumber);
WCHAR szSize[32];
if (0 <= (status = NtDeviceIoControlFile(hDisk, 0, 0, 0, &iosb,
IOCTL_DISK_GET_LENGTH_INFO, 0, 0, &li, sizeof(li))))
{
DbgPrint("Length = %S (%I64x)\n",
StrFormatByteSizeW(li.Length.QuadPart, szSize, RTL_NUMBER_OF(szSize)),
li.Length.QuadPart);
}
UNICODE_STRING ObjectName;
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName, OBJ_CASE_INSENSITIVE };
PVOID stack = alloca(guz);
union {
PVOID buf;
PDRIVE_LAYOUT_INFORMATION_EX pdli;
PSTORAGE_DEVICE_DESCRIPTOR psdd;
PCSTR psz;
};
STORAGE_PROPERTY_QUERY spq = { StorageDeviceProperty, PropertyStandardQuery };
ULONG cb = 0, rcb = sizeof(STORAGE_DEVICE_DESCRIPTOR) + 0x40, PartitionCount = 4;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
switch (status = (NtDeviceIoControlFile(hDisk, 0, 0, 0, &iosb,
IOCTL_STORAGE_QUERY_PROPERTY, &spq, sizeof(spq), buf, cb)))
{
case STATUS_SUCCESS:
case STATUS_BUFFER_OVERFLOW:
if (psdd->Version == sizeof(STORAGE_DEVICE_DESCRIPTOR))
{
if (psdd->Size > cb)
{
rcb = psdd->Size;
status = STATUS_BUFFER_OVERFLOW;
}
else
{
if (psdd->SerialNumberOffset)
{
DbgPrint("SerialNumber = %s\n", psz + psdd->SerialNumberOffset);
}
}
}
else
{
status = STATUS_INVALID_PARAMETER;
}
break;
}
} while (status == STATUS_BUFFER_OVERFLOW);
for (;;)
{
if (cb < (rcb = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[PartitionCount])))
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (0 <= (status = NtDeviceIoControlFile(hDisk, 0, 0, 0, &iosb,
IOCTL_DISK_GET_DRIVE_LAYOUT_EX, 0, 0, buf, cb)))
{
if (PartitionCount = pdli->PartitionCount)
{
PPARTITION_INFORMATION_EX PartitionEntry = pdli->PartitionEntry;
do
{
if (!PartitionEntry->PartitionNumber)
{
continue;
}
_itow(PartitionEntry->PartitionNumber, c, 10);
RtlInitUnicodeString(&ObjectName, sz);
DbgPrint("%wZ\nOffset=%S ", &ObjectName,
StrFormatByteSizeW(PartitionEntry->StartingOffset.QuadPart, szSize, RTL_NUMBER_OF(szSize)));
DbgPrint("Length=%S\n",
StrFormatByteSizeW(PartitionEntry->PartitionLength.QuadPart, szSize, RTL_NUMBER_OF(szSize)));
char PartitionName[256], *szPartitionName;
switch (PartitionEntry->PartitionStyle)
{
case PARTITION_STYLE_MBR:
DbgPrint("MBR: type=%x boot=%x", PartitionEntry->Mbr.PartitionType, PartitionEntry->Mbr.BootIndicator);
break;
case PARTITION_STYLE_GPT:
if (IsEqualGUID(PartitionEntry->Gpt.PartitionType, PARTITION_ENTRY_UNUSED_GUID))
{
szPartitionName = "UNUSED";
}
else if (IsEqualGUID(PartitionEntry->Gpt.PartitionType, PARTITION_SYSTEM_GUID))
{
szPartitionName = "SYSTEM";
}
else if (IsEqualGUID(PartitionEntry->Gpt.PartitionType, PARTITION_MSFT_RESERVED_GUID))
{
szPartitionName = "RESERVED";
}
else if (IsEqualGUID(PartitionEntry->Gpt.PartitionType, PARTITION_BASIC_DATA_GUID))
{
szPartitionName = "DATA";
}
else if (IsEqualGUID(PartitionEntry->Gpt.PartitionType, PARTITION_MSFT_RECOVERY_GUID))
{
szPartitionName = "RECOVERY";
}
else if (IsEqualGUID(PartitionEntry->Gpt.PartitionType, PARTITION_MSFT_SNAPSHOT_GUID))
{
szPartitionName = "SNAPSHOT";
}
else
{
sprintf(szPartitionName = PartitionName, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
PartitionEntry->Gpt.PartitionType.Data1,
PartitionEntry->Gpt.PartitionType.Data2,
PartitionEntry->Gpt.PartitionType.Data3,
PartitionEntry->Gpt.PartitionType.Data4[0],
PartitionEntry->Gpt.PartitionType.Data4[1],
PartitionEntry->Gpt.PartitionType.Data4[2],
PartitionEntry->Gpt.PartitionType.Data4[3],
PartitionEntry->Gpt.PartitionType.Data4[4],
PartitionEntry->Gpt.PartitionType.Data4[5],
PartitionEntry->Gpt.PartitionType.Data4[6],
PartitionEntry->Gpt.PartitionType.Data4[7]);
}
DbgPrint("[%s] %I64x \"%S\"",
szPartitionName,
PartitionEntry->Gpt.Attributes,
PartitionEntry->Gpt.Name);
break;
}
if (0 <= NtOpenFile(&hPartition, FILE_GENERIC_READ, &oa, &iosb,
FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT))
{
union {
BYTE bb[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 32*sizeof(WCHAR) ];
FILE_FS_ATTRIBUTE_INFORMATION ffai;
};
switch (NtQueryVolumeInformationFile(hPartition, &iosb, &ffai, sizeof(bb), FileFsAttributeInformation))
{
case STATUS_SUCCESS:
case STATUS_BUFFER_OVERFLOW:
DbgPrint(" \"%.*S\"\n", ffai.FileSystemNameLength >> 1 , ffai.FileSystemName);
break;
}
NtClose(hPartition);
}
} while (PartitionEntry++, --PartitionCount);
}
return ;
}
switch (status)
{
case STATUS_BUFFER_OVERFLOW:
PartitionCount = pdli->PartitionCount;
continue;
case STATUS_INFO_LENGTH_MISMATCH:
case STATUS_BUFFER_TOO_SMALL:
PartitionCount <<= 1;
continue;
default:
return ;
}
}
}
}
from another size we can get Device Instance ID from interface string by call CM_Get_Device_Interface_PropertyW with DEVPKEY_Device_InstanceId. after this we call CM_Locate_DevNodeW for get device instance handle.
CONFIGRET GetPropertyByInterface(PCSTR prefix, PCWSTR pszDeviceInterface)
{
ULONG cb = 0, rcb = 256;
PVOID stack = alloca(guz);
DEVPROPTYPE PropertyType;
CONFIGRET status;
union {
PVOID pv;
PWSTR DeviceID;
PBYTE pb;
};
do
{
if (cb < rcb)
{
rcb = cb = RtlPointerToOffset(pv = alloca(rcb - cb), stack);
}
status = CM_Get_Device_Interface_PropertyW(pszDeviceInterface, &DEVPKEY_Device_InstanceId, &PropertyType, pb, &rcb, 0);
if (status == CR_SUCCESS)
{
if (PropertyType == DEVPROP_TYPE_STRING)
{
DbgPrint("%sDeviceID = %S\n", prefix, DeviceID);
DEVINST dnDevInst;
if (CR_SUCCESS == (status = CM_Locate_DevNodeW(&dnDevInst, DeviceID, CM_LOCATE_DEVNODE_NORMAL)))
{
GetPropertyByDeviceID(prefix, dnDevInst);
}
}
else
{
status = CR_WRONG_TYPE;
}
break;
}
} while (status == CR_BUFFER_SMALL);
return status;
}
with device instance handle we can query many device properties via CM_Get_DevNode_PropertyW like:
DEVPKEY_Device_LocationInfo, DEVPKEY_NAME, DEVPKEY_Device_PDOName, DEVPKEY_Device_FirmwareVersion, DEVPKEY_Device_Model, DEVPKEY_Device_DriverVersion and many others - look full list in devpkey.h
finally we can call CM_Get_Parent and recursive query all this properties for parent device(s) until we not rich top of stack:
#define OPEN_PDO
void GetPropertyByDeviceID(PCSTR prefix, DEVINST dnDevInst)
{
#ifdef OPEN_PDO
HANDLE hFile;
IO_STATUS_BLOCK iosb;
UNICODE_STRING ObjectName;
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName, OBJ_CASE_INSENSITIVE };
#endif
CONFIGRET status;
ULONG cb = 0, rcb = 0x80;
PVOID stack = alloca(guz);
DEVPROPTYPE PropertyType;
union {
PVOID pv;
PWSTR sz;
PBYTE pb;
};
static struct
{
CONST DEVPROPKEY *PropertyKey;
PCWSTR PropertyName;
} PropertyKeys[] = {
{ &DEVPKEY_Device_PDOName, L"PDOName"},
{ &DEVPKEY_Device_Parent, L"Parent"},
{ &DEVPKEY_Device_DriverVersion, L"DriverVersion"},
{ &DEVPKEY_Device_LocationInfo, L"LocationInfo"},
{ &DEVPKEY_Device_FirmwareVersion, L"FirmwareVersion"},
{ &DEVPKEY_Device_Model, L"Model"},
{ &DEVPKEY_NAME, L"NAME"},
{ &DEVPKEY_Device_InstanceId, L"DeviceID"}
};
do
{
int n = RTL_NUMBER_OF(PropertyKeys);
do
{
CONST DEVPROPKEY *PropertyKey = PropertyKeys[--n].PropertyKey;
do
{
if (cb < rcb)
{
rcb = cb = RtlPointerToOffset(pv = alloca(rcb - cb), stack);
}
status = CM_Get_DevNode_PropertyW(dnDevInst, PropertyKey, &PropertyType, pb, &rcb, 0);
if (status == CR_SUCCESS)
{
if (PropertyType == DEVPROP_TYPE_STRING)
{
DbgPrint("%s%S=[%S]\n", prefix, PropertyKeys[n].PropertyName, sz);
#ifdef OPEN_PDO
if (!n)
{
// DEVPKEY_Device_PDOName can use in NtOpenFile
RtlInitUnicodeString(&ObjectName, sz);
if (0 <= NtOpenFile(&hFile, FILE_READ_ATTRIBUTES|SYNCHRONIZE, &oa,
&iosb, FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT))
{
NtClose(hFile);
}
}
#endif
}
}
} while (status == CR_BUFFER_SMALL);
} while (n);
if (!*--prefix) break;
} while (CM_Get_Parent(&dnDevInst, dnDevInst, 0) == CR_SUCCESS);
}
also string returned by DEVPKEY_Device_PDOName we can use in NtOpenFile call for open PDO device.
I'm looking for a command line program to add an entry to the import table of a PE file.
My goal is to add a new imported function from an external DLL to my EXE, and then with ollydbg insert new code using code caves. The new code will use the newly imported function.
Acctualy I've achived my goal, but to add a new entry to the import table I used Stud_PE, which is a GUI application and I want to automate this part of the process.
I'd consider programmatically solutions, but I'm affraid the PE structure is too complex for me to learn and explore in the time frame I have. Moreover if an implementation is already exists, it would be a shame not to use it. :-)
Found what is was looking for.
m-PEFile for c++: http://forum.exetools.com/showpost.php?s=17e7516356489bb9dd17e294e147ef96&p=60183&postcount=3
Also check out pefile for python: http://code.google.com/p/pefile/
And PE/COFF 4J for java: http://pecoff4j.sourceforge.net/
PE/COFF 4J has limited functionality in my opinion, but maybe you'll find it helpful.
Code: PEFile.h
/*******************************************************************************
******************************** Team AT4RE ********************************
********************************************************************************
******************* PLEASE DON'T CHANGE/REMOVE THIS HEADER *******************
********************************************************************************
** **
** Title: PEFile class. **
** Desc: A handy class to manipulate pe files. **
** Author: MohammadHi [ in4matics at hotmail dot com ] **
** WwW: AT4RE [ http://www.at4re.com ] **
** Date: 2008-01-28 **
** **
********************************************************************************
*******************************************************************************/
/*
[ PE File Format ]
---------------------
| DOS Header |
---------------------
| DOS Stub |
---------------------
| PE Header |
---------------------
| Section Table |
---------------------
| Padding |
---------------------
| Section 1 |
---------------------
| Section 2 |
---------------------
| ... |
---------------------
| Section n |
---------------------*/
//==============================================================================
#pragma once
#pragma pack(1)
//==============================================================================
#include <windows.h>
//==============================================================================
#define MAX_SECTION_COUNT 64
#define SECTION_IMPORT "#.import"
#define SECTION_RESERV "#.reserv"
//==============================================================================
struct PE_DOS_HEADER {
WORD Signature;
WORD LastPageBytes;
WORD NumberOfPages;
WORD Relocations;
WORD HeaderSize;
WORD MinMemory;
WORD MaxMemory;
WORD InitialSS;
WORD InitialSP;
WORD Checksum;
WORD InitialIP;
WORD InitialCS;
WORD RelocTableOffset;
WORD Overlay;
WORD Reserved1[4];
WORD OemId;
WORD OemInfo;
WORD Reserved2[10];
LONG PEHeaderOffset;
};
struct PE_DOS_STUB {
char* RawData;
DWORD Size;
};
struct PE_SECTION_DATA {
DWORD Offset;
char* RawData;
DWORD Size;
};
struct PE_IMPORT_FUNCTION {
char* FunctionName;
int FunctionId;
PE_IMPORT_FUNCTION* Next;
};
struct PE_IMPORT_DLL {
char* DllName;
PE_IMPORT_FUNCTION* Functions;
PE_IMPORT_DLL* Next;
};
//==============================================================================
typedef IMAGE_NT_HEADERS PE_NT_HEADERS;
typedef IMAGE_SECTION_HEADER PE_SECTION_HEADER;
//==============================================================================
class PEFile {
public:
PE_DOS_HEADER dosHeader;
PE_DOS_STUB dosStub;
PE_NT_HEADERS peHeaders;
PE_SECTION_HEADER sectionTable[MAX_SECTION_COUNT];
PE_SECTION_DATA reservedData;
PE_SECTION_DATA sections[MAX_SECTION_COUNT];
PE_IMPORT_DLL importTable;
PE_IMPORT_DLL newImports;
PEFile();
PEFile(char* filePath);
~PEFile();
bool loadFromFile(char* filePath);
bool loadFromMemory(char* memoryAddress);
bool saveToFile(char* filePath);
int addSection(char* name, DWORD size, bool isExecutable);
void addImport(char* dllName, char** functions, int functionCount);
void commit();
private:
char* peMemory;
void init();
bool readFileData(char* filePath);
bool checkValidity();
bool readHeaders();
bool readBody();
bool readImportTable();
bool writePadding(HANDLE fileHandle, long paddingSize);
void unloadFile();
void buildImportTable();
char* buildNewImports(DWORD baseRVA);
DWORD calcNewImportsSize(DWORD &sizeDlls, DWORD &sizeFunctions, DWORD &sizeStrings);
DWORD alignNumber(DWORD number, DWORD alignment);
DWORD rvaToOffset(DWORD rva);
DWORD offsetToRVA(DWORD offset);
void fixReservedData();
void fixHeaders();
void fixSectionTable();
};
//==============================================================================
Code: PEFile.cpp
/*******************************************************************************
******************************** Team AT4RE ********************************
********************************************************************************
******************* PLEASE DON'T CHANGE/REMOVE THIS HEADER *******************
********************************************************************************
** **
** Title: PEFile class. **
** Desc: A handy class to manipulate pe files. **
** Author: MohammadHi [ in4matics at hotmail dot com ] **
** WwW: AT4RE [ http://www.at4re.com ] **
** Date: 2008-01-28 **
** **
********************************************************************************
*******************************************************************************/
#include "PEFile.h"
#include <math.h>
//==============================================================================
#define DEBUG_ENABLED true;
#ifdef DEBUG_ENABLED
#define echo(x) MessageBox(0, x, "DEBUG", MB_ICONERROR);
#define echo2(x, y) { char v[256]; strcpy_s(v, 256, x); strcat_s(v, 256, y); echo(v); }
#define echo3(x, y, z) { char w[256]; strcpy_s(w, 256, x); strcat_s(w, 256, y); echo2(w, z); }
#else
#define echo(x) ;
#define echo2(x, y) ;
#define echo3(x, y, z) ;
#endif
//==============================================================================
PEFile::PEFile() {
init();
}
//==============================================================================
PEFile::PEFile(char* filePath) {
init();
loadFromFile(filePath);
}
//==============================================================================
PEFile::~PEFile() {
unloadFile();
}
//==============================================================================
void PEFile::init() {
peMemory = NULL;
ZeroMemory(&newImports, sizeof(PE_IMPORT_DLL));
}
//==============================================================================
bool PEFile::readFileData(char* filePath) {
// open the file for read
HANDLE fileHandle = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fileHandle == INVALID_HANDLE_VALUE) {
echo3("Couldn't open file : [", filePath, "]");
return false;
}
// get the file size
DWORD fileSize = GetFileSize(fileHandle, 0);
if (fileSize == 0) {
CloseHandle(fileHandle);
echo3("File size is ZeR0! : [", filePath, "]");
return false;
}
// allocate memory to read the pe file (note that we used VirtualAlloc not GlobalAlloc!)
peMemory = (char*)VirtualAlloc(NULL, fileSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (peMemory == NULL) {
CloseHandle(fileHandle);
echo("Couldn't allocate memory!");
return false;
}
DWORD bytesRead;
// read whole file data
if (!ReadFile(fileHandle, peMemory, fileSize, &bytesRead, NULL) || bytesRead != fileSize) {
CloseHandle(fileHandle);
echo3("Couldn't read file! : [", filePath, "]");
return false;
}
// close the file
CloseHandle(fileHandle);
return true;
}
//==============================================================================
bool PEFile::checkValidity() {
// 'dosHeader.Signature' must be "MZ" && 'peHeaders.Signature' must be "PE\0\0"
if (dosHeader.Signature != IMAGE_DOS_SIGNATURE || peHeaders.Signature != IMAGE_NT_SIGNATURE) {
unloadFile();
echo("Invalid PE file!");
return false;
}
if (peHeaders.FileHeader.NumberOfSections > MAX_SECTION_COUNT) {
unloadFile();
echo("Number of sections > MAX_SECTION_COUNT !");
return false;
}
return true;
}
//==============================================================================
bool PEFile::readHeaders() {
// read dos/pe headers
CopyMemory(&dosHeader, peMemory, sizeof(PE_DOS_HEADER));
dosStub.RawData = peMemory + sizeof(PE_DOS_HEADER);
dosStub.Size = dosHeader.PEHeaderOffset - sizeof(PE_DOS_HEADER);
CopyMemory(&peHeaders, peMemory + dosHeader.PEHeaderOffset, sizeof(PE_NT_HEADERS));
// check validity of the file to ensure that we loaded a "PE File" not another thing!
if (!checkValidity()) {
return false;
}
// read section table
ZeroMemory(sectionTable, sizeof(sectionTable));
CopyMemory(sectionTable, peMemory + dosHeader.PEHeaderOffset + sizeof(PE_NT_HEADERS),
peHeaders.FileHeader.NumberOfSections * sizeof(PE_SECTION_HEADER));
return true;
}
//==============================================================================
bool PEFile::readBody() {
// read reserved data
DWORD reservedDataOffset = dosHeader.PEHeaderOffset + sizeof(PE_NT_HEADERS) +
peHeaders.FileHeader.NumberOfSections * sizeof(PE_SECTION_HEADER);
reservedData.Offset = reservedDataOffset;
reservedData.RawData = peMemory + reservedDataOffset;
/*reservedData.Size = peHeaders.OptionalHeader.SizeOfHeaders - reservedDataOffset;*/
if (sectionTable[0].PointerToRawData > 0) {
reservedData.Size = sectionTable[0].PointerToRawData - reservedDataOffset;
} else {
reservedData.Size = sectionTable[0].VirtualAddress - reservedDataOffset;
}
// read sections
for (int i = 0; i < peHeaders.FileHeader.NumberOfSections; i++) {
sections[i].Offset = sectionTable[i].PointerToRawData;
sections[i].RawData = peMemory + sectionTable[i].PointerToRawData;
sections[i].Size = sectionTable[i].SizeOfRawData;
}
return true;
}
//==============================================================================
bool PEFile::readImportTable() {
DWORD tableRVA = peHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
DWORD tableOffset = rvaToOffset(tableRVA);
if (tableOffset == 0) {
return false;
}
ZeroMemory(&importTable, sizeof(PE_IMPORT_DLL));
IMAGE_IMPORT_DESCRIPTOR* importDesc = (IMAGE_IMPORT_DESCRIPTOR*)(peMemory + tableOffset);
IMAGE_THUNK_DATA* importThunk;
PE_IMPORT_DLL* importDll = &this->importTable;
PE_IMPORT_FUNCTION* importFunction;
while (true) {
importDll->DllName = (char*)(peMemory + rvaToOffset(importDesc->Name));
if (importDesc->OriginalFirstThunk > 0) {
importThunk = (IMAGE_THUNK_DATA*)(peMemory + rvaToOffset(importDesc->OriginalFirstThunk));
} else {
importThunk = (IMAGE_THUNK_DATA*)(peMemory + rvaToOffset(importDesc->FirstThunk));
}
importDll->Functions = new PE_IMPORT_FUNCTION();
ZeroMemory(importDll->Functions, sizeof(PE_IMPORT_FUNCTION));
importFunction = importDll->Functions;
while (true) {
if ((importThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG32) == IMAGE_ORDINAL_FLAG32) {
importFunction->FunctionId = IMAGE_ORDINAL32(importThunk->u1.Ordinal);
} else {
DWORD nameOffset = rvaToOffset(importThunk->u1.AddressOfData);
importFunction->FunctionName = (char*)(peMemory + nameOffset + 2);
}
importThunk = (IMAGE_THUNK_DATA*)((char*)importThunk + sizeof(IMAGE_THUNK_DATA));
if (importThunk->u1.AddressOfData == 0) {
break;
}
importFunction->Next = new PE_IMPORT_FUNCTION();
ZeroMemory(importFunction->Next, sizeof(PE_IMPORT_FUNCTION));
importFunction = importFunction->Next;
}
importDesc = (IMAGE_IMPORT_DESCRIPTOR*)((char*)importDesc + sizeof(IMAGE_IMPORT_DESCRIPTOR));
if (importDesc->Name == 0) {
break;
}
importDll->Next = new PE_IMPORT_DLL();
ZeroMemory(importDll->Next, sizeof(PE_IMPORT_DLL));
importDll = importDll->Next;
}
return true;
}
//==============================================================================
bool PEFile::loadFromFile(char* filePath) {
unloadFile();
return readFileData(filePath) &&
readHeaders() &&
readBody() &&
readImportTable();
}
//==============================================================================
bool PEFile::loadFromMemory(char* memoryAddress) {
unloadFile();
peMemory = memoryAddress;
return readHeaders()/* &&
readBody() &&
readImportTable()*/;
}
//==============================================================================
bool PEFile::saveToFile(char* filePath) {
commit();
buildImportTable();
// create the output file
HANDLE fileHandle = CreateFile(filePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (fileHandle == INVALID_HANDLE_VALUE) {
echo("Couldn't create file");
return false;
}
DWORD bytesWritten;
WriteFile(fileHandle, &dosHeader, sizeof(PE_DOS_HEADER), &bytesWritten, NULL);
WriteFile(fileHandle, dosStub.RawData, dosStub.Size, &bytesWritten, NULL);
writePadding(fileHandle, dosHeader.PEHeaderOffset - sizeof(PE_DOS_HEADER) - dosStub.Size);
WriteFile(fileHandle, &peHeaders, sizeof(PE_NT_HEADERS), &bytesWritten, NULL);
WriteFile(fileHandle, §ionTable, peHeaders.FileHeader.NumberOfSections * sizeof(PE_SECTION_HEADER), &bytesWritten, NULL);
WriteFile(fileHandle, reservedData.RawData, reservedData.Size, &bytesWritten, NULL);
for (int i = 0; i < peHeaders.FileHeader.NumberOfSections; i++) {
writePadding(fileHandle, sectionTable[i].PointerToRawData - GetFileSize(fileHandle, NULL));
WriteFile(fileHandle, sections[i].RawData, sections[i].Size, &bytesWritten, NULL);
}
CloseHandle(fileHandle);
return true;
}
//==============================================================================
bool PEFile::writePadding(HANDLE fileHandle, long paddingSize) {
if (paddingSize <= 0)
return false;
DWORD bytesWritten;
char* padding = new char[paddingSize];
memset(padding, 0, paddingSize);
WriteFile(fileHandle, padding, paddingSize, &bytesWritten, NULL);
delete padding;
return (bytesWritten == paddingSize);
}
//==============================================================================
void PEFile::unloadFile() {
if (peMemory != NULL) {
VirtualFree(peMemory, 0, MEM_RELEASE);
peMemory = NULL;
}
}
//==============================================================================
void PEFile::buildImportTable() {
DWORD sizeDlls = 0;
DWORD sizeFunctions = 0;
DWORD sizeStrings = 0;
DWORD newImportsSize = calcNewImportsSize(sizeDlls, sizeFunctions, sizeStrings);
// we'll move the old dll list to the new import table, so we'll calc its size
DWORD oldImportDllsSize = 0;
PE_IMPORT_DLL* importDll = &this->importTable;
while (importDll != NULL) {
oldImportDllsSize += sizeof(IMAGE_IMPORT_DESCRIPTOR);
importDll = importDll->Next;
}
// add a new section to handle the new import table
int index = addSection(SECTION_IMPORT, oldImportDllsSize + newImportsSize, false);
// copy old import dll list
DWORD oldImportTableRVA = peHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
DWORD oldImportTableOffset = rvaToOffset(oldImportTableRVA);
CopyMemory(sections[index].RawData, peMemory + oldImportTableOffset, oldImportDllsSize);
// copy new imports
char* newImportsData = buildNewImports(sectionTable[index].VirtualAddress + oldImportDllsSize);
CopyMemory(sections[index].RawData + oldImportDllsSize, newImportsData, newImportsSize);
peHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = sectionTable[index].VirtualAddress;
peHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = sectionTable[index].SizeOfRawData;
peHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0;
peHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0;
}
//==============================================================================
char* PEFile::buildNewImports(DWORD baseRVA) {
commit();
IMAGE_IMPORT_DESCRIPTOR importDesc;
IMAGE_THUNK_DATA importThunk;
PE_IMPORT_DLL* importDll;
PE_IMPORT_FUNCTION* importFunction;
DWORD sizeDlls = 0;
DWORD sizeFunctions = 0;
DWORD sizeStrings = 0;
DWORD newImportsSize = calcNewImportsSize(sizeDlls, sizeFunctions, sizeStrings);
DWORD offsetDlls = 0;
DWORD offsetFunctions = sizeDlls;
DWORD offsetStrings = sizeDlls + 2 * sizeFunctions;
char* buffer = new char[newImportsSize];
ZeroMemory(buffer, newImportsSize);
importDll = &newImports;
while (importDll != NULL) {
ZeroMemory(&importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR));
importDesc.OriginalFirstThunk = baseRVA + offsetFunctions;
importDesc.FirstThunk = baseRVA + offsetFunctions + sizeFunctions;
importDesc.Name = baseRVA + offsetStrings;
CopyMemory(buffer + offsetStrings, importDll->DllName, strlen(importDll->DllName));
offsetStrings += alignNumber((DWORD)strlen(importDll->DllName) + 1, 2);
CopyMemory(buffer + offsetDlls, &importDesc, sizeof(IMAGE_IMPORT_DESCRIPTOR));
offsetDlls += sizeof(IMAGE_IMPORT_DESCRIPTOR);
importFunction = importDll->Functions;
while (importFunction != NULL) {
ZeroMemory(&importThunk, sizeof(IMAGE_THUNK_DATA));
if (importFunction->FunctionId != 0) {
importThunk.u1.Ordinal = importFunction->FunctionId | IMAGE_ORDINAL_FLAG32;
} else {
importThunk.u1.AddressOfData = baseRVA + offsetStrings;
CopyMemory(buffer + offsetStrings + 2, importFunction->FunctionName, strlen(importFunction->FunctionName));
offsetStrings += 2 + alignNumber((DWORD)strlen(importFunction->FunctionName) + 1, 2);
}
CopyMemory(buffer + offsetFunctions, &importThunk, sizeof(IMAGE_THUNK_DATA));
CopyMemory(buffer + offsetFunctions + sizeFunctions, &importThunk, sizeof(IMAGE_THUNK_DATA));
offsetFunctions += sizeof(IMAGE_THUNK_DATA);
importFunction = importFunction->Next;
}
offsetFunctions += sizeof(IMAGE_THUNK_DATA);
importDll = importDll->Next;
}
return buffer;
}
//==============================================================================
DWORD PEFile::calcNewImportsSize(DWORD &sizeDlls, DWORD &sizeFunctions, DWORD &sizeStrings) {
PE_IMPORT_DLL* importDll = &this->newImports;
PE_IMPORT_FUNCTION* importFunction;
// calc added imports size
while (importDll != NULL) {
sizeDlls += sizeof(IMAGE_IMPORT_DESCRIPTOR);
sizeStrings += alignNumber((DWORD)strlen(importDll->DllName) + 1, 2);
importFunction = importDll->Functions;
while (importFunction != NULL) {
sizeFunctions += sizeof(IMAGE_THUNK_DATA);
if (importFunction->FunctionId == 0) {
sizeStrings += 2 + alignNumber((DWORD)strlen(importFunction->FunctionName) + 1, 2);
}
importFunction = importFunction->Next;
}
sizeFunctions += sizeof(IMAGE_THUNK_DATA); // for the terminator thunk data
importDll = importDll->Next;
}
sizeDlls += sizeof(IMAGE_IMPORT_DESCRIPTOR); // for the terminator import descriptor
return sizeDlls + 2 * sizeFunctions + sizeStrings;
}
//==============================================================================
int PEFile::addSection(char* name, DWORD size, bool isExecutable) {
if (peHeaders.FileHeader.NumberOfSections == MAX_SECTION_COUNT) {
return -1;
}
PE_SECTION_DATA &newSection = sections[peHeaders.FileHeader.NumberOfSections];
PE_SECTION_HEADER &newSectionHeader = sectionTable[peHeaders.FileHeader.NumberOfSections];
PE_SECTION_HEADER &lastSectionHeader = sectionTable[peHeaders.FileHeader.NumberOfSections - 1];
DWORD sectionSize = alignNumber(size, peHeaders.OptionalHeader.FileAlignment);
DWORD virtualSize = alignNumber(sectionSize, peHeaders.OptionalHeader.SectionAlignment);
DWORD sectionOffset = alignNumber(lastSectionHeader.PointerToRawData + lastSectionHeader.SizeOfRawData, peHeaders.OptionalHeader.FileAlignment);
DWORD virtualOffset = alignNumber(lastSectionHeader.VirtualAddress + lastSectionHeader.Misc.VirtualSize, peHeaders.OptionalHeader.SectionAlignment);
ZeroMemory(&newSectionHeader, sizeof(IMAGE_SECTION_HEADER));
CopyMemory(newSectionHeader.Name, name, (strlen(name) > 8 ? 8 : strlen(name)));
newSectionHeader.PointerToRawData = sectionOffset;
newSectionHeader.VirtualAddress = virtualOffset;
newSectionHeader.SizeOfRawData = sectionSize;
newSectionHeader.Misc.VirtualSize = virtualSize;
newSectionHeader.Characteristics = //0xC0000040;
IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA;
if (isExecutable) {
newSectionHeader.Characteristics |= IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE;
}
newSection.RawData = (char*)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sectionSize);
newSection.Size = sectionSize;
peHeaders.FileHeader.NumberOfSections++;
if (reservedData.Size > 0) {
reservedData.Size -= sizeof(IMAGE_SECTION_HEADER);
}
// return new section index
return peHeaders.FileHeader.NumberOfSections - 1;
}
//==============================================================================
void PEFile::addImport(char* dllName, char** functions, int functionCount) {
PE_IMPORT_DLL* importDll = &this->newImports;
PE_IMPORT_FUNCTION* importFunction;
if (newImports.DllName != NULL) {
while (importDll->Next != NULL) {
importDll = importDll->Next;
}
importDll->Next = new PE_IMPORT_DLL();
importDll = importDll->Next;
}
importDll->DllName = dllName;
importDll->Functions = new PE_IMPORT_FUNCTION();
importDll->Next = NULL;
importFunction = importDll->Functions;
importFunction->FunctionName = functions[0];
for (int i = 1; i < functionCount; i++) {
importFunction->Next = new PE_IMPORT_FUNCTION();
importFunction = importFunction->Next;
importFunction->FunctionName = functions[i];
}
importFunction->Next = NULL;
}
//==============================================================================
DWORD PEFile::alignNumber(DWORD number, DWORD alignment) {
return (DWORD)(ceil(number / (alignment + 0.0)) * alignment);
}
//==============================================================================
DWORD PEFile::rvaToOffset(DWORD rva) {
for (int i = 0; i < peHeaders.FileHeader.NumberOfSections; i++) {
if (rva >= sectionTable[i].VirtualAddress &&
rva < sectionTable[i].VirtualAddress + sectionTable[i].Misc.VirtualSize) {
return sectionTable[i].PointerToRawData + (rva - sectionTable[i].VirtualAddress);
}
}
return 0;
}
//==============================================================================
DWORD PEFile::offsetToRVA(DWORD offset) {
for (int i = 0; i < peHeaders.FileHeader.NumberOfSections; i++) {
if (offset >= sectionTable[i].PointerToRawData &&
offset < sectionTable[i].PointerToRawData + sectionTable[i].SizeOfRawData) {
return sectionTable[i].VirtualAddress + (offset - sectionTable[i].PointerToRawData);
}
}
return 0;
}
//==============================================================================
void PEFile::commit() {
fixReservedData();
fixHeaders();
fixSectionTable();
}
//==============================================================================
void PEFile::fixReservedData() {
DWORD dirIndex = 0;
for (dirIndex = 0; dirIndex < peHeaders.OptionalHeader.NumberOfRvaAndSizes; dirIndex++) {
if (peHeaders.OptionalHeader.DataDirectory[dirIndex].VirtualAddress > 0 &&
peHeaders.OptionalHeader.DataDirectory[dirIndex].VirtualAddress >= reservedData.Offset &&
peHeaders.OptionalHeader.DataDirectory[dirIndex].VirtualAddress < reservedData.Size) {
break;
}
}
if (dirIndex == peHeaders.OptionalHeader.NumberOfRvaAndSizes) {
return;
}
int sectionIndex = addSection(SECTION_RESERV, reservedData.Size, false);
CopyMemory(sections[sectionIndex].RawData, reservedData.RawData, reservedData.Size);
for (dirIndex = 0; dirIndex < peHeaders.OptionalHeader.NumberOfRvaAndSizes; dirIndex++) {
if (peHeaders.OptionalHeader.DataDirectory[dirIndex].VirtualAddress > 0 &&
peHeaders.OptionalHeader.DataDirectory[dirIndex].VirtualAddress >= reservedData.Offset &&
peHeaders.OptionalHeader.DataDirectory[dirIndex].VirtualAddress < reservedData.Size) {
peHeaders.OptionalHeader.DataDirectory[dirIndex].VirtualAddress +=
sectionTable[sectionIndex].VirtualAddress - reservedData.Offset;
}
}
reservedData.Size = 0;
}
//==============================================================================
void PEFile::fixHeaders() {
peHeaders.OptionalHeader.SizeOfHeaders = alignNumber(dosHeader.PEHeaderOffset + peHeaders.FileHeader.SizeOfOptionalHeader +
peHeaders.FileHeader.NumberOfSections * sizeof(PE_SECTION_HEADER), peHeaders.OptionalHeader.FileAlignment);
DWORD imageSize = peHeaders.OptionalHeader.SizeOfHeaders;
for (int i = 0; i < peHeaders.FileHeader.NumberOfSections; i++) {
imageSize += alignNumber(sectionTable[i].Misc.VirtualSize, peHeaders.OptionalHeader.SectionAlignment);
}
peHeaders.OptionalHeader.SizeOfImage = alignNumber(imageSize, peHeaders.OptionalHeader.SectionAlignment);
peHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
peHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
}
//==============================================================================
void PEFile::fixSectionTable() {
DWORD offset = peHeaders.OptionalHeader.SizeOfHeaders;
for (int i = 0; i < peHeaders.FileHeader.NumberOfSections; i++) {
sectionTable[i].Characteristics |= IMAGE_SCN_MEM_WRITE;
offset = alignNumber(offset, peHeaders.OptionalHeader.FileAlignment);
sectionTable[i].PointerToRawData = offset;
//sectionTable[i].SizeOfRawData = alignNumber(offset + sectionTable[i].Misc.VirtualSize, peHeaders.OptionalHeader.FileAlignment);
offset += sectionTable[i].SizeOfRawData;
}
}
//==============================================================================
#include "PEFile.h"
int main(int argc, char* argv[]) {
// Open the input file
PEFile pe("1.exe");
// Add "MessageBoxA" & "ShowWindow" functions to the import table
char* functions[] = { "MessageBoxA", "ShowWindow" };
pe.addImport("user32.dll", functions, 2);
// Add a new section named ".at4re" with size "0x1000" byte
pe.addSection(".at4re", 0x1000, false);
// Save the modified file
pe.saveToFile("1+.exe");
}
You can use the PeNet library to add a new import with just one line of code. For an example see here: Adding Imports
var peFile = new PeFile("myapp.exe");
peFile.AddImport("gdi32.dll", "StartPage");
I was looking for such program myself. I failed too.
But it is very easily done by hand.
If you need to automate it then you can make your own program.
Go to http://www.unknowncheats.me/forum/ or http://www.rohitab.com
People there will be able to help you write your own program.
I'm having a problem when I try to run the reduction program from the OpenCL in Action's sources.
Im using Visual Studio 2008. This is the error:
Unhandled exception in 0x013526a7 in Reduction.exe: 0xC00000FD: Stack
overflow.
And in the asm file the cursor is to
test dword ptr [eax],eax ; probe page.
I tried to debug it, but when I put a breakpoint in the main function, the debugging starts, but the program does not keep running.
I don't know what is the really problem.
These are the source files:
reduction.cpp
#define _CRT_SECURE_NO_WARNINGS
#define PROGRAM_FILE "reduction_complete.cl"
#define ARRAY_SIZE 1048576
#define KERNEL_1 "reduction_vector"
#define KERNEL_2 "reduction_complete"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef MAC
#include <OpenCL/cl.h>
#else
#include <CL/cl.h>
#endif
/* Find a GPU or CPU associated with the first available platform */
cl_device_id create_device() {
cl_platform_id platform;
cl_device_id dev;
int err;
/* Identify a platform */
err = clGetPlatformIDs(1, &platform, NULL);
if(err < 0) {
perror("Couldn't identify a platform");
exit(1);
}
/* Access a device */
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &dev, NULL);
if(err == CL_DEVICE_NOT_FOUND) {
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_CPU, 1, &dev, NULL);
}
if(err < 0) {
perror("Couldn't access any devices");
exit(1);
}
return dev;
}
/* Create program from a file and compile it */
cl_program build_program(cl_context ctx, cl_device_id dev, const char* filename) {
cl_program program;
FILE *program_handle;
char *program_buffer, *program_log;
size_t program_size, log_size;
int err;
/* Read program file and place content into buffer */
program_handle = fopen(filename, "r");
if(program_handle == NULL) {
perror("Couldn't find the program file");
exit(1);
}
fseek(program_handle, 0, SEEK_END);
program_size = ftell(program_handle);
rewind(program_handle);
program_buffer = (char*)malloc(program_size + 1);
program_buffer[program_size] = '\0';
fread(program_buffer, sizeof(char), program_size, program_handle);
fclose(program_handle);
/* Create program from file */
program = clCreateProgramWithSource(ctx, 1,
(const char**)&program_buffer, &program_size, &err);
if(err < 0) {
perror("Couldn't create the program");
exit(1);
}
free(program_buffer);
/* Build program */
err = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);
if(err < 0) {
/* Find size of log and print to std output */
clGetProgramBuildInfo(program, dev, CL_PROGRAM_BUILD_LOG,
0, NULL, &log_size);
program_log = (char*) malloc(log_size + 1);
program_log[log_size] = '\0';
clGetProgramBuildInfo(program, dev, CL_PROGRAM_BUILD_LOG,
log_size + 1, program_log, NULL);
printf("%s\n", program_log);
free(program_log);
exit(1);
}
return program;
}
int main() {
/* OpenCL structures */
cl_device_id device;
cl_context context;
cl_program program;
cl_kernel vector_kernel, complete_kernel;
cl_command_queue queue;
cl_event start_event, end_event;
cl_int i, err;
size_t local_size, global_size;
/* Data and buffers */
float data[ARRAY_SIZE];
float sum, actual_sum;
cl_mem data_buffer, sum_buffer;
cl_ulong time_start, time_end, total_time;
/* Initialize data */
for(i=0; i<ARRAY_SIZE; i++) {
data[i] = 1.0f*i;
}
/* Create device and determine local size */
device = create_device();
err = clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_GROUP_SIZE,
sizeof(local_size), &local_size, NULL);
if(err < 0) {
perror("Couldn't obtain device information");
exit(1);
}
/* Create a context */
context = clCreateContext(NULL, 1, &device, NULL, NULL, &err);
if(err < 0) {
perror("Couldn't create a context");
exit(1);
}
/* Build program */
program = build_program(context, device, PROGRAM_FILE);
/* Create data buffer */
data_buffer = clCreateBuffer(context, CL_MEM_READ_WRITE |
CL_MEM_USE_HOST_PTR, ARRAY_SIZE * sizeof(float), data, &err);
sum_buffer = clCreateBuffer(context, CL_MEM_WRITE_ONLY,
sizeof(float), NULL, &err);
if(err < 0) {
perror("Couldn't create a buffer");
exit(1);
};
/* Create a command queue */
queue = clCreateCommandQueue(context, device,
CL_QUEUE_PROFILING_ENABLE, &err);
if(err < 0) {
perror("Couldn't create a command queue");
exit(1);
};
/* Create kernels */
vector_kernel = clCreateKernel(program, KERNEL_1, &err);
complete_kernel = clCreateKernel(program, KERNEL_2, &err);
if(err < 0) {
perror("Couldn't create a kernel");
exit(1);
};
/* Set arguments for vector kernel */
err = clSetKernelArg(vector_kernel, 0, sizeof(cl_mem), &data_buffer);
err |= clSetKernelArg(vector_kernel, 1, local_size * 4 * sizeof(float), NULL);
/* Set arguments for complete kernel */
err = clSetKernelArg(complete_kernel, 0, sizeof(cl_mem), &data_buffer);
err |= clSetKernelArg(complete_kernel, 1, local_size * 4 * sizeof(float), NULL);
err |= clSetKernelArg(complete_kernel, 2, sizeof(cl_mem), &sum_buffer);
if(err < 0) {
perror("Couldn't create a kernel argument");
exit(1);
}
/* Enqueue kernels */
global_size = ARRAY_SIZE/4;
err = clEnqueueNDRangeKernel(queue, vector_kernel, 1, NULL, &global_size,
&local_size, 0, NULL, &start_event);
if(err < 0) {
perror("Couldn't enqueue the kernel");
exit(1);
}
printf("Global size = %zu\n", global_size);
/* Perform successive stages of the reduction */
while(global_size/local_size > local_size) {
global_size = global_size/local_size;
err = clEnqueueNDRangeKernel(queue, vector_kernel, 1, NULL, &global_size,
&local_size, 0, NULL, NULL);
printf("Global size = %zu\n", global_size);
if(err < 0) {
perror("Couldn't enqueue the kernel");
exit(1);
}
}
global_size = global_size/local_size;
err = clEnqueueNDRangeKernel(queue, complete_kernel, 1, NULL, &global_size,
NULL, 0, NULL, &end_event);
printf("Global size = %zu\n", global_size);
/* Finish processing the queue and get profiling information */
clFinish(queue);
clGetEventProfilingInfo(start_event, CL_PROFILING_COMMAND_START,
sizeof(time_start), &time_start, NULL);
clGetEventProfilingInfo(end_event, CL_PROFILING_COMMAND_END,
sizeof(time_end), &time_end, NULL);
total_time = time_end - time_start;
/* Read the result */
err = clEnqueueReadBuffer(queue, sum_buffer, CL_TRUE, 0,
sizeof(float), &sum, 0, NULL, NULL);
if(err < 0) {
perror("Couldn't read the buffer");
exit(1);
}
/* Check result */
actual_sum = 1.0f * (ARRAY_SIZE/2)*(ARRAY_SIZE-1);
if(fabs(sum - actual_sum) > 0.01*fabs(sum))
printf("Check failed.\n");
else
printf("Check passed.\n");
printf("Total time = %lu\n", total_time);
/* Deallocate resources */
clReleaseEvent(start_event);
clReleaseEvent(end_event);
clReleaseMemObject(sum_buffer);
clReleaseMemObject(data_buffer);
clReleaseKernel(vector_kernel);
clReleaseKernel(complete_kernel);
clReleaseCommandQueue(queue);
clReleaseProgram(program);
clReleaseContext(context);
return 0;
}
reduction_complete.cl
__kernel void reduction_vector(__global float4* data,
__local float4* partial_sums) {
int lid = get_local_id(0);
int group_size = get_local_size(0);
partial_sums[lid] = data[get_global_id(0)];
barrier(CLK_LOCAL_MEM_FENCE);
for(int i = group_size/2; i>0; i >>= 1) {
if(lid < i) {
partial_sums[lid] += partial_sums[lid + i];
}
barrier(CLK_LOCAL_MEM_FENCE);
}
if(lid == 0) {
data[get_group_id(0)] = partial_sums[0];
}
}
__kernel void reduction_complete(__global float4* data,
__local float4* partial_sums, __global float* sum) {
int lid = get_local_id(0);
int group_size = get_local_size(0);
partial_sums[lid] = data[get_local_id(0)];
barrier(CLK_LOCAL_MEM_FENCE);
for(int i = group_size/2; i>0; i >>= 1) {
if(lid < i) {
partial_sums[lid] += partial_sums[lid + i];
}
barrier(CLK_LOCAL_MEM_FENCE);
}
if(lid == 0) {
*sum = partial_sums[0].s0 + partial_sums[0].s1 +
partial_sums[0].s2 + partial_sums[0].s3;
}
}
I dont know what causes the stackoverflow...
I don't see any recursion so my guess is the float data[ARRAY_SIZE]; where #define ARRAY_SIZE 1048576 is putting 4MB on the stack which is pretty large. Try changing that to a dynamic allocation.