expertenaustausch > comp.os.* > comp.os.unix.programming

Thomas Orgelmacher (03.10.2018, 16:44)
Hallo Zusammen!

Ich stehe auf dem Schlauch. Und zwar richtig.

Ich will mit libexif EXIF-Daten parsen (ok, das ist jetzt nicht wirklich
überraschend).

Folgender Code (Ausschnitt und um den Inhalt von "switch(entry->tag)" gekürzt):

-------------------- schnipp --------------------
void cb_entry(ExifEntry *entry, void *data)
{
exifdata_t *ed = data;

if(! is_suppressed_tag(entry->tag) /* tags we (at least I) don't need */
&& entry->size < BUFFSIZE)
{
exif_entry_get_value(entry, buf, sizeof(buf));

if(!buf[0])
ed = NULL;
else
{
switch(entry->tag)
{
/* lauter cases eben... */
};
}
}
}

void cb_content(ExifContent *content, void *data)
{
exif_content_foreach_entry(content, cb_entry, data);
}
-------------------- schnapp --------------------

Das Problem ist: cb_entry wird nicht aus cb_content von
exif_content_foreach_entry per Callback aufgerufen.
Ich habe mir das im Assembler angeschaut und da steht ganz
klar ein "callq", welches einfach übergangen wird.

Und jetzt wird richtig schräg: gdb meint dazu:
"Line 1 of "exif.c" is at address 0x401fb4 <cb_entry> but contains no code."

Compiler Flags (gcc 5.5) sind "-g -Wall", also wirklich nicht wirklich spannend.

Der Ursprung des Codes ist eine Python3 Extension, die eigentlich auch
weitgehend funktioniert. Ich hatte nur gelegentliche segfaults, die ich
jetzt ohne den Python Kontext isolieren wollte.
Aus dem Grund habe ich die Python Abhängigkeiten wieder ausgebaut und es
tut gar nichts mehr.

Der Code ist kein Geheimnis, wenn jemand mehr sehen will: sachts eben was.

Ich stoße mich vor allem an "<cb_entry> but contains no code." und der
Tatsache, daß das "callq" nicht ausgeführt wird.

Klingelt das bei irgendwem?

Gruß, Thomas

PS.: Entschuldigt bitte den Post an dclc. Ich weiß, daß hier kein C-Problem
vorliegt aber da sitzt Potential, daß ich gern dabei hätte...
Stefan Ram (03.10.2018, 17:12)
Thomas Orgelmacher <trash> writes:
>Das Problem ist: cb_entry wird nicht aus cb_content von
>exif_content_foreach_entry per Callback aufgerufen.
>Ich habe mir das im Assembler angeschaut und da steht ganz
>klar ein "callq", welches einfach übergangen wird.


Falls Du Assembler-Programmierer bist, dann ersetzt die
callq-Zeile durch folgende fünf Zeilen:

<Ausgabe eines Textes auf die Konsole>
<callq-Aufruf einer prominenten Funktion, der auf jeden Fall
erfolgreich ausgeführt werden können sollte>
<callq einer Funktion mit ähnlichen Eigenschaften wie cb_entry>
<der ursprüngliche callq-Aufruf von cb_entry>
<Ausgabe eines Textes auf die Konsole>

und starte dann das Programm, um zu sehen, was dann dort
passiert.

Ok, das ist jetzt ein sehr primitiver Hinweis, aber ich weiß
ja nicht, was Du schon alles probiert hast:

Ersetze cb_entry einmal durch:

void cb_entry(ExifEntry *entry, void *data){ abort(); }

und lasse das so, solange es nicht aufgerufen wird.

An dem »abort()« kannst Du es dann erkennen, falls es
doch einmal aufgerufen werden sollte.

Dann rufe es auch einmal von »main()« aus auf.

main(){ cb_entry( 0, 0 ); }

. Jetzt müßte das Programm abbrechen.

>Und jetzt wird richtig schräg: gdb meint dazu:
>"Line 1 of "exif.c" is at address 0x401fb4 <cb_entry> but contains no code."


Zeile 1 von exif.c enthält keinen Code? Verstehe ich auch nicht!
Stefan Reuther (03.10.2018, 17:55)
Am 03.10.2018 um 16:44 schrieb Thomas Orgelmacher:
> -------------------- schnipp --------------------
> void cb_entry(ExifEntry *entry, void *data)
> {
> exifdata_t *ed = data;
> if(! is_suppressed_tag(entry->tag) /* tags we (at least I) don't need */


Wie ist denn 'is_suppressed_tag' definiert?

> Das Problem ist: cb_entry wird nicht aus cb_content von
> exif_content_foreach_entry per Callback aufgerufen.
> Ich habe mir das im Assembler angeschaut und da steht ganz
> klar ein "callq", welches einfach übergangen wird.
> Und jetzt wird richtig schräg: gdb meint dazu:
> "Line 1 of "exif.c" is at address 0x401fb4 <cb_entry> but contains no
> code."


Wenn du schon im Debugger bist: was sagt denn 'disas cb_entry'?

"Line 1 of exif.c" dürfte ja die Zeile mit dem Funktionskopf sein, dafür
wird wirklich kein Code generiert. Aber 'disas cb_entry' zeigt dir
alles, was er für die Funktion hat.

Wenn der Compiler zu dem Schluss kommt, dass 'is_suppressed_tag' immer
false liefert, wird er z.B. die Funktion 'cb_entry' zu einem einzelnen
'retq'-Befehl zusammenstreichen.

Stefan
Thomas Orgelmacher (03.10.2018, 18:55)
Am 03.10.18 um 17:55 schrieb Stefan Reuther:
> Wenn du schon im Debugger bist: was sagt denn 'disas cb_entry'?


Eine ganze Menge:

Dump of assembler code for function cb_entry:
0x0000000000401fb4 <+0>: push %rbp
0x0000000000401fb5 <+1>: mov %rsp,%rbp
0x0000000000401fb8 <+4>: push %r12
0x0000000000401fba <+6>: push %rbx
0x0000000000401fbb <+7>: sub $0x20,%rsp
0x0000000000401fbf <+11>: mov %rdi,-0x28(%rbp)
0x0000000000401fc3 <+15>: mov %rsi,-0x30(%rbp)
0x0000000000401fc7 <+19>: mov -0x30(%rbp),%rax
0x0000000000401fcb <+23>: mov %rax,-0x18(%rbp)
0x0000000000401fcf <+27>: mov 0x20234a(%rip),%rax # 0x604320
<stderr@>
0x0000000000401fd6 <+34>: mov %rax,%rcx
0x0000000000401fd9 <+37>: mov $0x10,%edx
0x0000000000401fde <+42>: mov $0x1,%esi
0x0000000000401fe3 <+47>: mov $0x4029dc,%edi
0x0000000000401fe8 <+52>: callq 0x400f80 <fwrite@plt>
0x0000000000401fed <+57>: mov -0x28(%rbp),%rax
0x0000000000401ff1 <+61>: mov (%rax),%eax
0x0000000000401ff3 <+63>: mov %eax,%edi
0x0000000000401ff5 <+65>: callq 0x401988 <is_suppressed_tag>
0x0000000000401ffa <+70>: test %eax,%eax
0x0000000000401ffc <+72>: jne 0x4021ea <cb_entry+566>
0x0000000000402002 <+78>: mov -0x28(%rbp),%rax
0x0000000000402006 <+82>: mov 0x18(%rax),%eax
0x0000000000402009 <+85>: cmp $0x7fff,%eax
0x000000000040200e <+90>: ja 0x4021ea <cb_entry+566>
0x0000000000402014 <+96>: mov -0x28(%rbp),%rax
0x0000000000402018 <+100>: mov $0x8000,%edx
0x000000000040201d <+105>: mov $0x604360,%esi
0x0000000000402022 <+110>: mov %rax,%rdi
0x0000000000402025 <+113>: callq 0x400e20 <exif_entry_get_value@plt>
0x000000000040202a <+118>: mov -0x28(%rbp),%rax
0x000000000040202e <+122>: mov 0x18(%rax),%ebx
0x0000000000402031 <+125>: mov -0x28(%rbp),%rax
0x0000000000402035 <+129>: mov 0x4(%rax),%eax
0x0000000000402038 <+132>: mov %eax,%edi
0x000000000040203a <+134>: callq 0x400ef0 <exif_format_get_name@plt>
0x000000000040203f <+139>: mov %rax,%r12
0x0000000000402042 <+142>: mov -0x28(%rbp),%rax
0x0000000000402046 <+146>: mov (%rax),%eax
0x0000000000402048 <+148>: mov %eax,%edi
0x000000000040204a <+150>: callq 0x400e70 <exif_tag_get_name@plt>
0x000000000040204f <+155>: mov %rax,%rdx
0x0000000000402052 <+158>: mov -0x28(%rbp),%rax
0x0000000000402056 <+162>: mov (%rax),%eax
0x0000000000402058 <+164>: mov $0x604360,%r9d
0x000000000040205e <+170>: mov %ebx,%r8d
0x0000000000402061 <+173>: mov %r12,%rcx
0x0000000000402064 <+176>: mov %eax,%esi
0x0000000000402066 <+178>: mov $0x4029ed,%edi
0x000000000040206b <+183>: mov $0x0,%eax
0x0000000000402070 <+188>: callq 0x400e50 <printf@plt>
0x0000000000402075 <+193>: movzbl 0x2022e4(%rip),%eax # 0x604360 <buf>
0x000000000040207c <+200>: test %al,%al
0x000000000040207e <+202>: jne 0x40208d <cb_entry+217>
0x0000000000402080 <+204>: movq $0x0,-0x18(%rbp)
0x0000000000402088 <+212>: jmpq 0x4021ea <cb_entry+566>
0x000000000040208d <+217>: mov -0x28(%rbp),%rax
0x0000000000402091 <+221>: mov (%rax),%eax
0x0000000000402093 <+223>: cmp $0x132,%eax
0x0000000000402098 <+228>: je 0x4021b2 <cb_entry+510>
0x000000000040209e <+234>: cmp $0x132,%eax
0x00000000004020a3 <+239>: ja 0x4020c3 <cb_entry+271>
0x00000000004020a5 <+241>: cmp $0x110,%eax
0x00000000004020aa <+246>: je 0x402100 <cb_entry+332>
0x00000000004020ac <+248>: cmp $0x131,%eax
0x00000000004020b1 <+253>: je 0x40211c <cb_entry+360>
0x00000000004020b3 <+255>: cmp $0x10f,%eax
0x00000000004020b8 <+260>: je 0x40214b <cb_entry+407>
0x00000000004020be <+266>: jmpq 0x4021ea <cb_entry+566>
0x00000000004020c3 <+271>: cmp $0x9004,%eax
0x00000000004020c8 <+276>: je 0x40218a <cb_entry+470>
0x00000000004020ce <+282>: cmp $0x9004,%eax
0x00000000004020d3 <+287>: ja 0x4020e5 <cb_entry+305>
0x00000000004020d5 <+289>: cmp $0x9003,%eax
0x00000000004020da <+294>: je 0x402171 <cb_entry+445>
0x00000000004020e0 <+300>: jmpq 0x4021ea <cb_entry+566>
0x00000000004020e5 <+305>: cmp $0xa002,%eax
0x00000000004020ea <+310>: je 0x4021da <cb_entry+550>
0x00000000004020f0 <+316>: cmp $0xa003,%eax
0x00000000004020f5 <+321>: je 0x4021dd <cb_entry+553>
0x00000000004020fb <+327>: jmpq 0x4021ea <cb_entry+566>
0x0000000000402100 <+332>: mov -0x18(%rbp),%rax
0x0000000000402104 <+336>: add $0x100,%rax
0x000000000040210a <+342>: mov $0x604360,%esi
0x000000000040210f <+347>: mov %rax,%rdi
0x0000000000402112 <+350>: callq 0x400e10 <strcpy@plt>
0x0000000000402117 <+355>: jmpq 0x4021ea <cb_entry+566>
0x000000000040211c <+360>: mov -0x18(%rbp),%rax
0x0000000000402120 <+364>: movzbl 0x100(%rax),%eax
0x0000000000402127 <+371>: test %al,%al
0x0000000000402129 <+373>: jne 0x4021e0 <cb_entry+556>
0x000000000040212f <+379>: mov -0x18(%rbp),%rax
0x0000000000402133 <+383>: add $0x100,%rax
0x0000000000402139 <+389>: mov $0x604360,%esi
0x000000000040213e <+394>: mov %rax,%rdi
0x0000000000402141 <+397>: callq 0x400e10 <strcpy@plt>
0x0000000000402146 <+402>: jmpq 0x4021e0 <cb_entry+556>
0x000000000040214b <+407>: mov -0x18(%rbp),%rax
0x000000000040214f <+411>: movzbl 0x100(%rax),%eax
0x0000000000402156 <+418>: test %al,%al
0x0000000000402158 <+420>: jne 0x4021e3 <cb_entry+559>
0x000000000040215e <+426>: mov -0x18(%rbp),%rax
0x0000000000402162 <+430>: mov $0x604360,%esi
0x0000000000402167 <+435>: mov %rax,%rdi
0x000000000040216a <+438>: callq 0x400e10 <strcpy@plt>
0x000000000040216f <+443>: jmp 0x4021e3 <cb_entry+559>
0x0000000000402171 <+445>: mov -0x18(%rbp),%rax
0x0000000000402175 <+449>: add $0x200,%rax
0x000000000040217b <+455>: mov $0x604360,%esi
0x0000000000402180 <+460>: mov %rax,%rdi
0x0000000000402183 <+463>: callq 0x400e10 <strcpy@plt>
0x0000000000402188 <+468>: jmp 0x4021ea <cb_entry+566>
0x000000000040218a <+470>: mov -0x18(%rbp),%rax
0x000000000040218e <+474>: movzbl 0x200(%rax),%eax
0x0000000000402195 <+481>: test %al,%al
0x0000000000402197 <+483>: jne 0x4021e6 <cb_entry+562>
0x0000000000402199 <+485>: mov -0x18(%rbp),%rax
0x000000000040219d <+489>: add $0x200,%rax
0x00000000004021a3 <+495>: mov $0x604360,%esi
0x00000000004021a8 <+500>: mov %rax,%rdi
0x00000000004021ab <+503>: callq 0x400e10 <strcpy@plt>
0x00000000004021b0 <+508>: jmp 0x4021e6 <cb_entry+562>
0x00000000004021b2 <+510>: mov -0x18(%rbp),%rax
0x00000000004021b6 <+514>: movzbl 0x200(%rax),%eax
0x00000000004021bd <+521>: test %al,%al
0x00000000004021bf <+523>: jne 0x4021e9 <cb_entry+565>
0x00000000004021c1 <+525>: mov -0x18(%rbp),%rax
0x00000000004021c5 <+529>: add $0x200,%rax
0x00000000004021cb <+535>: mov $0x604360,%esi
0x00000000004021d0 <+540>: mov %rax,%rdi
0x00000000004021d3 <+543>: callq 0x400e10 <strcpy@plt>
0x00000000004021d8 <+548>: jmp 0x4021e9 <cb_entry+565>
0x00000000004021da <+550>: nop
0x00000000004021db <+551>: jmp 0x4021ea <cb_entry+566>
0x00000000004021dd <+553>: nop
0x00000000004021de <+554>: jmp 0x4021ea <cb_entry+566>
0x00000000004021e0 <+556>: nop
0x00000000004021e1 <+557>: jmp 0x4021ea <cb_entry+566>
0x00000000004021e3 <+559>: nop
0x00000000004021e4 <+560>: jmp 0x4021ea <cb_entry+566>
0x00000000004021e6 <+562>: nop
0x00000000004021e7 <+563>: jmp 0x4021ea <cb_entry+566>
0x00000000004021e9 <+565>: nop
0x00000000004021ea <+566>: nop
0x00000000004021eb <+567>: add $0x20,%rsp
0x00000000004021ef <+571>: pop %rbx
0x00000000004021f0 <+572>: pop %r12
0x00000000004021f2 <+574>: pop %rbp
0x00000000004021f3 <+575>: retq
End of assembler dump.

> "Line 1 of exif.c" dürfte ja die Zeile mit dem Funktionskopf sein, dafür
> wird wirklich kein Code generiert. Aber 'disas cb_entry' zeigt dir
> alles, was er für die Funktion hat.
> Wenn der Compiler zu dem Schluss kommt, dass 'is_suppressed_tag' immer
> false liefert, wird er z.B. die Funktion 'cb_entry' zu einem einzelnen
> 'retq'-Befehl zusammenstreichen.


int is_suppressed_tag(int tag)
{
static int suppressed_tags[] =
{
EXIF_TAG_PRINT_IMAGE_MATCHING,
EXIF_TAG_MAKER_NOTE,
EXIF_TAG_XP_KEYWORDS,
EXIF_TAG_USER_COMMENT,
EXIF_TAG_COPYRIGHT,
EXIF_TAG_PADDING,
EXIF_TAG_XP_SUBJECT,
EXIF_TAG_XP_KEYWORDS,
EXIF_TAG_XP_AUTHOR,
EXIF_TAG_XP_COMMENT,
EXIF_TAG_XP_TITLE,
EXIF_TAG_DEVICE_SETTING_DESCRIPTION,
EXIF_TAG_IMAGE_DESCRIPTION,
-1
};

for(int i = 0; suppressed_tags[i] != -1; i++)
if(suppressed_tags[i] == tag)
return 1;

return 0;
}

Ich sehe nicht, was da mal eben wegoptimiert werden könnte...

Gruß, Thomas
Stefan Ram (03.10.2018, 19:37)
Thomas Orgelmacher <trash> writes:
>int is_suppressed_tag(int tag)
>{
> static int suppressed_tags[] =
> {
> EXIF_TAG_PRINT_IMAGE_MATCHING, ....
>Ich sehe nicht, was da mal eben wegoptimiert werden könnte...


main.c

#include <stdio.h>

#define EXIF_A 0
#define EXIF_B 1
#define EXIF_C 2

static void escape( volatile void * p )
{ asm volatile( "" : : "g"(p) : "memory" ); }

int is_suppressed_tag( int tag )
{ static int suppressed_tags[] =
{ EXIF_A,
EXIF_B,
-1 };

for( int i = 0; suppressed_tags[ i ]!= -1; ++i )
if( suppressed_tags[ i ]== tag )return 1;
return 0; }

__attribute__ ((noinline)) int f340()
{ return is_suppressed_tag( EXIF_A ); }

__attribute__ ((noinline)) int f341()
{ return is_suppressed_tag( EXIF_C ); }

int main()
{ { int result = f340(); escape( &result ); }
{ int result = f341(); escape( &result ); }}

Assembler-Ausgabe (mit gcc ... -O3 ...)

f340:
....
movl $1, %eax
ret
....
f341:
....
xorl %eax, %eax
ret
....
Edzard Egberts (04.10.2018, 08:22)
Thomas Orgelmacher wrote:
[..]
> -------------------- schnapp --------------------
> Das Problem ist: cb_entry wird nicht aus cb_content von
> exif_content_foreach_entry per Callback aufgerufen.


Wenn es eben nicht geht, kannst Du den ExifContent doch auch direkt parsen:

for (unsigned i= 0; i< content->count; ++i)
cb_entry((*content)[i], nullptr);

Das müsste Dir zeigen, ob exif_content_foreach_entry() kaputt ist, oder
das Problem tatsächlich im cb_entry() liegt.
Thomas Orgelmacher (04.10.2018, 19:18)
Am 04.10.18 um 08:22 schrieb Edzard Egberts:
> Wenn es eben nicht geht, kannst Du den ExifContent doch auch direkt parsen:
> for (unsigned i= 0; i< content->count; ++i)
>     cb_entry((*content)[i], nullptr);
> Das müsste Dir zeigen, ob exif_content_foreach_entry() kaputt ist, oder das
> Problem tatsächlich im cb_entry() liegt.


Meine Güte, man kann ja sowas von daneben sein...

Wenn man exif_data_new_from_data(mapped, size) mit size = 0 aufruft, findet
es tatsächlich nichts... unglaublich :-)

Vielen Dank an alle für's Schubsen!

Thomas
Ähnliche Themen