Like 团 怎 么 退 款&asymp. sig.;Like 团 怎 么 申 请 退 款↑

S00|LOFTER(乐乎) - 记录生活,发现同好
LOFTER for ipad —— 记录生活,发现同好
记录生活,发现同好
57位喜爱 #S00 的小伙伴邀你来玩
查看高清大图
喜欢并收藏内容
关注达人获取动态
评论私信与同好交流
10秒注册,查看更多优质内容
{if x.type==1}
{if !!x.title}${x.title}{/if}
{if !!x.digest}${x.digest}{/if}
{if x.type==2}
{if x.type==3}
{if x.type==4}
加入 LOFTER 开通功能特权
查看高清大图
喜欢并收藏内容
关注达人获取动态
评论私信与同好交流IBM 编译器中国开发团队
Blogs parecidos
364Entradas
Actualizada
Número de "me gusta" 260
Comentarios 121
135Entradas
Actualizada
Número de "me gusta" 10
Comentarios 2
279Entradas
270000KJQC
Actualizada
Número de "me gusta" 345
Comentarios 40
1857Entradas
Actualizada
Número de "me gusta" 1.960
Comentarios 246
262Entradas
Actualizada
Número de "me gusta" 435
Comentarios 22
Blogs de ideación parecidos
270003UGDT
Actualizada
Comentarios 8
Archivador
Autores de blog
Ordenar por:
270003XAW2
2.072 vistas
原文地址:
从XLC/C++ AIX/Linux V11.1和XL FORTRAN for AIX/Linux V13.1开始,一个非常有价值的新特性已经融入了编译器之中,通过指定-qlistfmt=xml选项,编译器可以生成XML格式的优化报告。一些子选项可供用户掌控他们想要产生的信息以及输出的格式或者文件。举例:-qlistfmt=xml=[no]inlines子选项允许用户开启/禁止关于内联汇编的转化报表的生成。并且-qlistfmt=xml=stylesheet=a.xsl子选项可以使用户自定义XML样式表来显示XML报告。为了帮助用户更好地理解这个新特性,我们已经创建了一个沙盒示例,并与其他相关示例一起置于: 您也可以通过点击以下链接,直接访问XML报表示例的相关文档:我们期望在未来的新产品发布中,位于其他平台上的XL C/C++/FORTRAN编译器也实现了XML优化报告特性,并且逐渐增加附加子选项,以更好的视图来服务用户,增进用户的理解,并且改善编译器的优化。欢迎尝试使用该新特性,并提供任何反馈。
7.180 vistas
原文链接:
假期通常是个回顾过去的好时候。这里就是我正在思考的上个月使我产生&ah-hah&瞬间的一个问题。
当你编译下面的C++程序的时候,你可能认为模块(module)中的对象会先编译并先初始化。
这种假设可能得不到预期的结果。
#include &string&
&&& // 译者注: 加上这行
class CObjet {
&&&& static const string STRINGX;
#include &X.h&
&&& // 译者注: 这行可以不要
const string CObjet::STRINGX = &001&;
#include &iostream&
#include &X.h&
const string STRINGY= CObjet::STRINGX;
int main () {
cout && &CObjet::STRINGX [& &&CObjet::STRINGX && &]& &&
cout && &STRINGY [& &&& STRINGY && &]& &&
如果用下面的命令来编译:
xlC -c -I./ X.cpp -o X.o
xlC -c -I./ Y.cpp -o Y.o
xlC -o binary X.o Y.o
然后得到的结果如下:
CObjet::STRINGX [001]
STRINGY []&&& // 译者注: 该结果是AIX平台的, Linux平台可能会Segmentation fault
从这个结果来看,STRINGY并没有像预期的那样初始化为STRINGX
STRINGX和STRINGY是全局静态对象。STRINGY的初始化取决于STRINGX的初始化。两者定义在不同的源文件中。
虽然C++语言规范规定了同一个文件中这类对象的初始化顺序(按照定义的顺序),但并没有规定在跨文件或者库时这些对象的初始化顺序。
因此虽然模块X.o先编译, STRINGX仍可能会在STRINGY之后初始化, 这就形成了一个空的STRINGY.
取决于编译器和操作系统缓存中当前的值, STRINGY甚至可能包含了垃圾数据并导致程序运行时崩溃。
为了解决这个问题,一些开发者将每个非局部静态对象都移动到自己的函数中,并声明为静态的。并让这些函数返回这个静态对象的引用, 然后按照自己期望的对象初始化顺序来调用这些函数.虽然这通常是个可移植的方法,但是这需要修改代码。
XL C/C++编译器可以使得这项工作变得简单。你可以使用-qpriority或-qmkshrobj=priority(译者注: linux上只有-qmkshrobj形式) 或 -Wm,-c选项来指定定义在不同文件或者库中的静态对象的初始化顺序。这些选项会给每个模块赋予一个优先级值,然后根据该值来控制对象的初始化顺序。
包含主函数main()的模块通常优先级为0. 值越小表示优先级越高,在上面的例子中,可以在编译X.o的时候指定-qpriority=-100从而保证X.o中的对象在Y.o对象初始化之前初始化。
同样的,如果你想把X.o创建到一个共享库中,那么可以在创建该库的时候指定-qmkshrobj=-100。
即,你可以用下面的命令来编译:
xlC -c -I./ -qpriority=-100 X.cpp -o X.o
xlC -c -I./ Y.cpp -o Y.o
xlC -o binary X.o Y.o
或者, 创建共享库:
xlC -c -I./ X.cpp -o X.o
xlC -c -I./ Y.cpp -o Y.o
xlC -qmkshrobj=-100 -o libX.so X.o
xlC -o binary -btrl Y.o -L. -lX
这时执行程序就会得到如下结果:
CObjet::STRINGX [001]
STRINGY [001]
如果想了解更多,请访问
你有相似的经验吗?你有没有什么诸如当你遇到一个编程问题而有&ah-hah&的时刻要分享?
可以在这里发表评论或者把示例代码发给我,或许我们能帮忙将这些问题聚焦在此来帮助更多人。
总之,祝各位新年快乐!
2.594 vistas
软件开发者们在开发产品级代码时常会面对一个艰难的选择,你总是希望你的代码性能优越,这意味着你需要在高优化级别上编译它;同时,你可能希望调试你加入产品中的这份二进制代码,而不是编译时没有经过优化的源文件。如果你尝试过调试优化过的代码,你可能已经知道这其中的难处了:源代码语句不按顺序执行,或者在你希望它们执行的时候它们没有;
变量没有按预期地进行更新;
变量没有定义的值,甚至没有一个定义的标识;
在调试器内对变量的更新对程序执行不起作用。
这不是因为编译器出了什么差错,它设计的初衷就是为了保留你程序的结果和外部行为,而不是它在调试器中的瞬态和内部行为。
新一代编译器
在2012年年中IBM发布了IBM
Power系统上C/C++和Fortran编译器的最新版本:XL
C/C++编译器V12.1和XL
Fortran编译器V14.1,均对应AIX和Power
Linux平台。这些新的编译器提供了一系列数值的选择以供调试优化过的代码,你可以自由选择在完全优化代码和完全可调试代码之间的权衡级别。在大多数其它编译器中,开发者有两个可用的选择:
编译一个没有优化的调试版本(例如使用-g),或
一个优化过的版本,但是可调试性较差(例如使用-O2)。
C++ V12.1和XL Fortran
V14.1编译器中,你可以使用一系列-g的值,从-g0一直到-g9,调试级别越低,在调试期间观测的错误可能性越大,这意味着你可以自由权衡可调试性和性能。在程序优化时编译器会保障各级别的可调试性,并在调试过程中在保证预期行为的情况下有效地将应用的性能最大化。
编译器在优化过程中经常会在不改变程序结果的前提下重新编排逻辑,编译器这么做可能是为了直接提高程序的性能,或者是为了让接下来的优化能提高程序的性能。此外,为了提高处理器吞吐量或是其它的原因,当主优化阶段完成、指令生成时,源代码行相关的指令序列可能也会被重新排序,
这些编译器的优化有两个主要的影响:第一,如果你按源代码的行数单步跟踪程序,那么程序可能不会按照正确的顺序执行。第二,如果你在一个过程的开始设了个断点,没有人能保证这过程的参数在这时会含有正确的值,程序甚至根本不会进入这个过程。这是因为编译器在优化过程中将被调用的过程代码内联至调用处。在XL
C/C++和 XL
Fortran的早先版本中,旧的-g行为会生成全部调试信息,但它对于一个优化过的程序是否有用就不得而知了,因此,在用-g和-O编译的程序中,当你试图去调试并观测某个特定过程被调用时的参数是什么时,你甚至不能确定过程入口处设立的断点是否可以让你看到这些参数的实际值。然而,-g3或更高的调试级别可以保证在过程的入口处参数是有效且可见的。
优化代码中的某些语句可能并没有被执行到,而另一些可能比在它们之前的语句更先被执行。如果你在一个给定的源代码行中设立一个断点,你不能确定逻辑上在这之前的行中变量被赋的值是否正确。例如,考虑一下程序段:10 x=x+1;11
fl=fl1/fl2;12 y=y+1;
如果我们在第11行设立一个断点并运行程序,调试器会在与第11行关联的第一条指令处停下,但此时第10行可能还没有被执行过,因为第10行与第11行是无关的,编译器可以自由将它们调换顺序。如果你想要单步执行这段代码,你可能会发现我们在停在第10行前就已经执行到了11行,这是一个很强的信号(但不是一定的),说明与第10行相关的指令都还没有被执行到。 在这个例子中编译器会将除法尽早做好,因为除法指令有很长的延迟,而此时一个先进的流水线式处理器可以在除法进行时继续工作,这样的话没有关联上的行为,例如将x的值读入寄存器并将它加1,可能会同时进行。假设我们对在第11行处的除法结果有兴趣。在没有优化过的程序中,我们只需要单步到第12行,再查看fl的值。但在优化过的程序中,单步到第12步不能保证所有与第11行相关的操作都已经完成,我们可能已经完成了除法但还没有将结果存回内存,因此,确定变量已经可以显示正确结果的唯一方法是单步执行机器指令直到你看到除法运算的结果被写回了内存空间。如果你只关心结果的值(而不是验证是否更新了变量),取而代之你可以在除法运算更新了其目标寄存器的同时打印它的值。
C/C++ V12.1或 XL Fortran
V14.1的-g8或更高的选项编译程序时,调试器可以得到每个可执行语句开始时程序的状态。在先前的例子上使用-g8可以确保当你到达第11行的断点时,第10行的加法已经完成,而且你可以通过调试器来得到其结果。
被移除的变量
调试器总是认为变量在内存中,因此当你在调试器中检查变量时,它会打印出程序分配给该变量的内存位置中的内容。然而,编译器在优化过程中总是尽可能在它认为安全的情况下避免更新与变量相关联的内存地址,这么设计是为了提高性能,因为执行读取与存储的代价非常大。如果编译器可以在变量被修改后将它保存在寄存器中,那么它就不会把它立即写回内存里,甚至永远都不会写。这么做的副作用是相当于在调试器面前将变量隐藏了起来。考虑一个标准的索引变量ii,请看如下例子:
ii=0; ii&10; i++)21
sum=sum+array[ii];
在这个例子中,大多数编译器在编译时会将ii和sum保存在寄存器里。如果在循环完成后要使用ii的话,编译器会再生成代码来将ii写回到内存位置,但大多数情况下,如果寄存器中存放的值再也没用了的话就会被舍弃(覆写)。这可能会使得调试过程变得复杂:
调试器辨认不出变量。当你试图打印、查看ii时,调试器不知道它是什么;
调试器只能提供ii的类型和上下文信息,但不能显示它的值;
调试器可以显示赋给ii的内存位置的值,但这个值已经过期或无用了。
同样,新的-g8或-g9选项可以解决这些与被移除的变量或未知的变量值相关的问题。
改变变量的值
在程序运行时用调试器改变变量的值来改变程序的行为是另一种调试应用的技术。显然,如果编译器将变量的引用优化掉或是使得调试器找不到变量在机器级的位置,那么这技术也就没法使用了,甚至更糟的情况是它貌似有用,但是却没有得到预期的效果。
这是-g8与-g9之间的主要区别。对于-g8,编译器提供了程序在每条可执行语句开始处的状态,但不保证编程人员可以在调试时修改变量的值。另一方便,-g9使得你可以修改程序变量并让此修改影响程序的执行。显而易见,编译器在生成代码时必须保证各程序变量能在调试时被修改,因此在上述循环的例子中,在每个循环的迭代里ii都应该能从内存中被读取到。这会大幅度地影响性能,因此只有在你觉得上述特质对你维护代码至关重要时才应该在产品级的代码上使用-g9。在绝大多数情况下,检测程序时你完全不需要这么做就可以理解程序的行为并找出潜在的漏洞,这时,我们更推荐使用-g8。
内联和经优化的调试
编译器在优化时经常将被调用的过程“内联”至调用的地方,换句话说,他们用被调用的过程体的拷贝来取代调用操作。这么做是为了消除调用的代价,同时,那些依赖于调用处上下文的优化可以作用到内联的代码上。然而,内联会使得调试变得更加困难。
当一个过程被内联后,不再存在调用指令。大多数调试器都提供“Step”命令和“next”命令,这两者在面对语句时行为是一致的,但在面对调用时不同,“Step”进入被调用的过程的第一条语句,而“Next”会跨过(执行完)调用(除非在执行被调用过程时遇到了断点)。
由于当过程内联时不再有调用指令,Step和Next命令对于一个内联过程的“调用”具有相同的效果,如果没有带扩展功能的调试器支持的话,两条命令都会执行内联函数的代码,就好像用户正步入调用一样。
在XL编译器中,高调试级别在处理内联上相较于早先的产品有了巨大的进步。在-g8或更高的级别中,编译器会在每个内联代码的语句中插入状态信息,使得你可以在调试一个内联过程的调用时单步执行被调用过程的各语句、查看到正确的变量值(就算它依赖于正确的作用域信息)、甚至在内联过程中改变本地变量的值(-g9)。然而,“Next”命令不会跨过内联过程,而是像“Step”那样步入内联过程的代码。
要注意的是,当你单步运行内联函数中的语句且当调试器可以跟踪到运行程序的内联过程时,该过程不会出现在调试器的调用栈上。
请记住,当你提高经优化的调试级别,你增加了可调试性,但潜在地降低了编译完后程序的性能。选择一个符合你调试需求的调试级别是非常重要的,你需要最小化调试对性能的影响。在很多情况下,相较于未做优化的二进制代码,即使在高调试级别下编译器还是可以将性能的大幅度增强。例如,一个用-O2
-g8编译的典型程序的运行速度是-O2编译出的相同程序的80%,对于当需要可调试性时只用-g编译的传统方法来说,这是一个实质性的进步。以下是对各个-g级别效果的简单说明:
-g0:没有调试信息。这是缺省设置。-g1:生成只含有行号和源文件名字的调试信息,没有符号表信息。
-g2:“传统的”-g行为。在优化时,编译器生成所有调试数据,但是不保证其可用性和准确性。所有之前提到过的问题都有可能发生。
-g3,-g4:类似-g2,另外,调试器可以在过程开始处查看到函数的参数值。
-g5,-g6,-g7:类似-g3,另外,在循环前后、分支语句、过程调用和各过程的第一句可执行语句中,调试器可以查看到程序的状态。
-g8:类似-g3,另外,在每条源代码行中调试器都能看到程序的状态。
-g9:类似-g8,另外,用户可以在调试器中修改用户变量来确实地改变程序行为。
使用优化调试的好处
C/C++和 XL
Fortran编译器的用户为他们的产品二进制码创建单独的调试和优化版本,这是因为他们考虑到封装调试版本给性能带来的影响和代码经优化后可调试性上的问题。我们可以将优化版本封装起来交给客户,同时用调试版本来解决实际使用时发现的问题。虽然这是一个不错的方法,但一些开发商更希望(甚至要求)它们的产品在生产环境中具有完全的可调试性。
我们之所以支持将可调试的二进制代码封装进产品交给客户,是因为这确保当遇到漏洞时,客户的运行环境与技术人员在调查该漏洞时的调试环境是一样的。优化过的代码与未优化的代码之间总是可能会存在行为上的差异,也存在优化过程自身错误地改变程序行为的罕见情况。封装可调试的二进制代码可以解决这些问题,尤其是对于那些重视可重现性的开发商。
有了拥有新优化调试支持的Power系统下AIX和Linux平台的XL
C/C++和 XL
Fortran编译器,你可以同时拥有两项的优势:一个符合你实际维护需要的可调试级别,和一个缩小完全可调试性和完全优化之间差距的性能级别。最好的一点是,相比起传统的仅支持调试而不优化的传统编译方法来说,即使现在你使用了最高级别的优化调试,你仍可以使你的应用得到巨大的性能提升。
2.026 vistas
IBM XL 编译器旨在优化 Power Systems 服务器的基础架构。从增强到支持最新的标准,再从高度调优的数学库到行业领先的优化技术,XL 编译器都能够让您最充分地利用您的软件和硬件投资。
270003XMER
2.594 vistas
好久不见,这里我们将继续来探讨一下Power Linux下64位程序的一些基本概念。 如前面所述,查看反汇编代码是学习新的体系结构的最好方法,也是最基本的方法。 我们继续研究简单的反汇编代码,从简单的例子来挖掘PowerPC 64 ELF ABI里面另一个概念: 回溯表 (Traceback Table)。
对于如下代码: funcaddr.c
int func() {
return 2012;}int main(void) {
我们可以得到如下反汇编: xlc -q64 funcaddr.c -c -o funcaddr.oobjdump -d funcaddr.o
& funcaddr.o.dis 0000 &.func&:
38 60 07 dc
4e 80 00 20
00 00 00 00
00 00 20 40
.long 0x2040
00 00 00 01
00 00 00 08
00 04 66 75
.long 0x46675
6e 63 00 00
r3,r19,0 仔细查看反汇编代码,我们会再发现另一个很奇怪的地方: 在blr 之后还会有.long 0x0,和xoris r3,r19,0等似乎很杂乱的指令我们的例子足够简单,所以我们可以确认函数体只需要 li r3,2012 和 blr 两条指令即可, 也不会有额外的静态数据存在,难道是编译器生成了垃圾指令吗? 仔细查看其他函数,我们会发现在每一个函数后面都有这么一串指令, 而且长短不同!!:
0020 &.main&:
7c 08 02 a6
f8 21 ff 91
r1,-112(r1)
f8 01 00 80
r0,128(r1)
4b ff ff d5
60 00 00 00
38 60 00 00
e8 01 00 80
r0,128(r1)
7c 08 03 a6
38 21 00 70
4e 80 00 20
00 00 00 00
00 00 20 41
.long 0x2041
80 00 00 01
00 00 00 28
.long 0x28
00 04 6d 61
.long 0x46d61
69 6e 00 00
r14,r11,0 这些到底是什么指令呢? 做什么用的呢? 能不能删掉呢? 为了搞清楚这些指令是什么东西,我们来看一下汇编代码。
xlc -q64 funcaddr.c -S
&.text&,&ax&
7.LC.The_Code:
r3,r0,2012
BO_ALWAYS,CR0_LT
.long 0.LC.The_CodeTB12:/* Traceback table */
/* VERSION=0 */
/* Bits on: has_tboff,
/* Bits on: name_present,
/* Bits on:
FP_SAVED=0 */
GP_SAVED=0*/
/* FIXEDPARMS=0 */
/* FLOATPARMS=0 */
.long 8 /* tb_offset: 0x8 */
/* Function name length: 4 */
.long 0x66756e63
/* Name: func */
在指令块的后面,我们发现确实多了.long 0, .LC.The_CodeTB12:, .byte等一系列的东西。通过注释我们可以了解到这些是& Traceback table&!
那么Traceback table又是干什么用的呢? 为什么要生成?查看PowerPC 64 ELF ABI, 我们可以发现有一段关于回溯表的的描述(
原来, PPC64使用回溯表来支持调试和异常处理,这样异常处理程序获取到函数的相关信息。 回溯表又分为两部分,一部分是强制的域(Mandatory Fileds), 这里包含版本,源代码语言,是否有TOC表等; 另外一部分是可选的域(Optional Fields),包含函数名长度,函数名,alloca所用基址寄存器等。
汇编代码会把使用到的域通过注释的方式显示出来 , 如 /* LANG
= C */, /* Name: func */ 等。
一个典型的使用回溯表的例子是: 异常处理程序在打印调用堆栈时往往要显示各个函数名,
函数名信息就可以通过读取回溯表的可选域 Name 来显示。
既然是支持调试和异常处理的,那么就说明这部分不是必要的部分了,在一些特殊的情况下,如不需要调试或不支持异常处理的情况下,
我们确实可以通过编译器的选项
来缩小或删掉这个表格。
xlc -q64 funcaddr.c -qtbtable=small -cobjdump -d funcaddr.o 0000 &.func&:
38 60 07 dc
4e 80 00 20
00 00 00 00
00 00 20 00
.long 0x2000
00 00 00 01
00 00 00 08
...0020 &.main&:
7c 08 02 a6
f8 21 ff 91
r1,-112(r1)
f8 01 00 80
r0,128(r1)
4b ff ff d5
60 00 00 00
38 60 00 00
e8 01 00 80
r0,128(r1)
7c 08 03 a6
38 21 00 70
4e 80 00 20
00 00 00 00
00 00 20 01
.long 0x2001
80 00 00 01
00 00 00 28
.long 0x28
对比之前的,我们可以发现后面的指令确实变少了,可选域部分不见了,再试试-qtbtable=none:
xlc -q64 funcaddr.c -qtbtable=none -cobjdump -d funcaddr.o 0000 &.func&:
38 60 07 dc
4e 80 00 20
...0020 &.main&:
7c 08 02 a6
f8 21 ff 91
r1,-112(r1)
f8 01 00 80
r0,128(r1)
4b ff ff d5
60 00 00 00
38 60 00 00
e8 01 00 80
r0,128(r1)
7c 08 03 a6
38 21 00 70
4e 80 00 20
恩,这回世界清静了,blr后面再也没有额外的指令了。。。。
好了,回溯表的基本介绍就到这儿了,作为一个练习,
你也许可以试试写一段代码来从目标文件中显示对应代码段的函数名?
推荐你使用今天介绍的回溯表的信息,
当然对于一般没有被strip过的目标文件,你也可以使用符号表,
结合我们上次提到的函数描述符来实现这一目标。
如果在练习当中遇到一些问题,欢迎回复和我进行讨论。
参考文献: 1.
64-bit PowerPC ELF Application Binary Interface Supplement 1.9
-qtbtable http://pic./infocenter/lnxpcomp/v111v131/topic/com.ibm.xlcpp111.linux.doc/compiler_ref/opt_tbtable.html
270003XMER
4.382 vistas
& & & & 随着硬件技术的发展,越来越多的系统开始转向了64位。PowerPC体系结构是一个天生的64位系统,
但是要从32位转向64位并不是那么简单,会遇到很多问题。
这里我们将探讨一下Power Linux下64位程序的一些基本概念。
& & & & 学习一种新的体系结构的最好的方法就是从底层开始,从研究汇编代码和体系结构相关的ABI开始。
这里我们将通过一段简单的代码和反汇编来介绍PowerPC 64 ELF ABI里面很重要的一个概念: 函数描述符。
对于如下代码: funcaddr.c &
&int func()&{
& &return 2011;
int main(void)&{
& & & & func();
我们可以得到如下反汇编:
&xlc -q64 funcaddr.c -o funcaddr
objdump -dr funcaddr && funcaddr.dis
0680 &.func&:
& & : & 38 60 00 64 & & li & & &r3,100
& & : & 4e 80 00 20 & & blr
& & : & 00 00 00 00 & & .long 0x0
& & 1000068c: & 00 00 20 40 & & .long 0x2040
& & : & 00 00 00 01 & & .long 0x1
& & : & 00 00 00 08 & & .long 0x8
& & : & 00 04 66 75 & & .long 0x46675
& & 1000069c: & 6e 63 00 00 & & xoris & r3,r19,0
仔细查看反汇编代码,我们会发现一个奇怪的地方:
函数名前面都加了一个dot(.) 前缀:&& & &func =& .&
查找一下符号表:&
objdump -t funcaddr |grep func
funcaddr: & & file format elf64-powerpc
0000 l & &df *ABS* &0000 & & & & & & &funcaddr.c
0c88 g & & F .opd & 0020 & & & & & & &func
这里的函数名符号还是func,没有dot(.) 前缀;
但是函数func的地址&0c88 和 反汇编的.func函数地址&0680 &不一样啊?&
这是为什么呢?&func和.func是什么关系呢?&
而且func被放置到了.opd 段,这个.opd段又是做什么用的呢?&
查看PowerPC 64 ELF ABI, 我们可以发现有一段关于函数描述符的描述:
PPC64 ABI&
3.2.5 Function Descriptors
A function descriptor is a three doubleword data structure that contains the following values:
* The first doubleword contains the address of the entry point of the function.
* The second doubleword contains the TOC base address for the function.
* The third doubleword contains the environment pointer for languages such as Pascal and PL/1.
For an externally visible function, the value of the symbol with the same name as the function is the address of the function descriptor.&
Symbol names with a dot (.) prefix are reserved for holding entry point addresses.&
The value of a symbol named &.FN& is the entry point of the function &FN&.
The value of a function pointer in a language like C is the address of the function descriptor.
原来,&PPC64使用函数描述符来进行函数调用,函数描述符里面会保存函数的入口地址和TOC表基地址等。
这里就解决了我们上述的两个疑问:
1. dot(.)前缀的符号是为了区分真正的函数符号,它指向的是用来保存函数描述符的表项的地址。
2. C语言中取函数地址所得的函数指针,实际上是函数描述符的地址。所以,符号表中func函数地址是函数描述符的地址。
3. 函数描述符存储在.opd段里,所以,真正的func函数的入口地址,应该在.opd段中才能找到。
查看一下.opd段的内容来验证上面的描述:&
readelf -x .opd funcaddr&
&Hex dump of section '.opd':
& 0x1b8 18d00 ................
& 0x00 004f4 ................
& 0xd00 00000 ................
& 0x30 18d00 .......0........
& 0x00 00880 ................
& 0xd00 00000 ................
& 0x30 18d00 .......0........
& 0x00 005d0 ................
& 0xd00 00000 ................
& 0x80 18d00 ................
& 0x00 006a0 ................
& 0x1d00 00000 ................
& 0x1e0 18d00 ................
& 0x100 006f0 ................
& 0x1d00 00000 ................
& 0x1c0 18d00 ................
& 0x100 & & & & & & & & & ........
查看里面的内容我们可以看到 符号表中函数func的地址对应的函数描述符数据为:
& 0x10010c88 00680 18d00 ................
根据ABI的描述,我们可以知道第一个双字的数据是真正的函数入口地址:
&这一个地址和我们反汇编所得到的.func的地址是一致的。
&0680&&.func&
到此为止,至少我们可以看懂PowerPC 64的反汇编代码了。&
本blog仅仅是抛砖引玉的介绍一下函数描述符的基本概念,函数描述符的使用还有很多很有趣的地方,
感兴趣的同学可以参考ABI手册或相关参考文献进行进一步研究。&
参考文献:&
1. &PPC64: odd opd section, binelf, &
2. &Notes on comparision between the PPC64 ABI and the IA64 ABI&
270004DBCT
2.562 vistas
原文地址:
我们的客户多次向我们抱怨说他们的代码时常在老版本的编译器上能够正常编译,但是使用了新版本的编译器则无法工作了。经过仔细的研究客户提供的测试用例样本,我们发现他们能有一份可以工作的代码拷贝,运气确实很好。其实,编译失败是可预期的,因为他们违反了ansi-aliasing规则。
我们中大多数人都没有严格地遵循c和c++标准定义的规则。虽然aliasing规则建议使用兼容类型的左值访问一个对象,但是我们常常为了使代码能够工作而不得不破坏这条规则。默认的,在z/Os上的xlc使用ANSIALIAS选项进行编译。源文件中的指针访问的是与指针具有相同类型的对象,基于这个假设,编译器会使用两种或者以上的方法确定存储位置,即aliased。比如说,如果我们有一个结构体struct
s,包含两个成员s1与s2。S的存储空间与s.s1和s.s2的存储空间重叠。但是s.s1与s.s2不重叠。这一信息对于激进的编译器优化是十分关键的。它允许一些load指令上移以及一些store指令下移。对于指令执行顺序的重新调整是很有必要的,可以增加并发执行的代码数量。
将一个指针转换成指向不同对象的指针是一个常用的c语言技术。每一次类型不匹配,xlc都会产生一个警告,后面也许会跟着一条指示性消息。如果你使用-qflag=E,S,或者U,将诊断消息级别设为错误或者更高,或者你将所有编译器消息重定向到一个你很少会去看的日志文件中,你可能不会注意到这些警告或者指示性消息。通常你第一次注意到一个问题是当你执行了代码并获得一个错误的结果。你已经破坏了规则,现在该怎么办呢?你可以使用低级别的优化选项来编译那些与ansi
alias不兼容的代码,比如使用OPT0编译。级别越高的优化,优化技术就越激进的依赖于aliasing信息。你可以使用宏指令#pragma
option_override(func,&OPt(LEVEL,0)&)为每一个子过程中关闭优化。
你可以使用-qnoansialias编译选项或者使用cc工具,这个工具会默认将noansialias选项传给编译器。这可能不是最令人满意的解决办法,因为它常常会严重降低性能。比如,gcc
使用-O3和–qnoansialias选项进行编译,会降低可执行文件的运行速度20%。
你可以自己解决这个不兼容问题。
(E)的第3.10章,第15段如此表述:如果一个程序试图通过以下类型之外的左值访问一个对象存储的值,它的行为是未定义的:
对象动态类型cv(译者注:const,volatile)
修饰的对象动态类型有符号或者无符号的对象动态类型有符号或者无符号的cv修饰的对象动态类型一个集合类型包含了上述类型的成员(递归的包括了一个子集合的成员或者包含的集合)对象的动态类型的基类类型(可能是cv修饰的)char或者unsigned
例子:/*alias.c*/int
foo(char *c){char a[100];char *cptr =*(int *)cptr
= *(int*)c;return 0;}xlc -c alias.c -O3
-qlist=./ -qflag=i -qinfoINFORMATIONAL
CCN3495 ./alias.c:5 Pointer type conversion found.INFORMATIONAL
CCN3374 ./alias.c:5 Pointer types &int*& and &char*&
are not compatible.INFORMATIONAL CCN3495 ./alias.c:5 Pointer type
conversion found.INFORMATIONAL CCN3374 ./alias.c:5 Pointer types
&int*& and &char*& are not
compatible.INFORMATIONAL CCN3415 ./alias.c:7 The external
function definition &foo& is never referenced.
2.236 vistas
很高兴的在这里告诉大家,我们刚刚发布了几款Linux编译器产品的最新PTF (Program Temporary Fix).以上是我们最新版本的Linux编译器(XL C/C++ 11.1 & XL Fortran 13.1)自2010年8月正式发布以来的第一次更新,除了修正客户汇报的一些缺陷及问题,它还提供了对Red Hat Enterprise Linux Version 6.0的全面支持。想随时了解我们编译器产品的最新更新吗? 请点击并收藏
3.958 vistas
原文地址:
为了提高在性能方面的表现,开发人员们花了很大努力去优化他们的应用程序。然而,还有一个简单的方法也可以达到同样的效果,那就是使用新版本XLC编译器。尽管性能提升的幅度会由于不同应用程序的设计和用途而不同,但是如果程序需要处理大量的数据,性能上的差别就显而易见了。 下面是一个简单的示例程序:该程序需要处理大量的数据,从而计算两个多维度矩阵的相乘。(注意:该程序本身没有对矩阵相乘算法做过优化处理)由于数据量很大,CPU内寄存器的数量不足以有效地保存程序中的所有数据值。解决方案就是把数据放到内存中去!示例源代码文件. 让我们看一下在AIX平台上使用v90,v10.1以及v11.1这三个不同版本编译器时,程序的性能表现。可以看到,当编译器版本从v9升级到v11.1,程序的运行时间有很显著的改善(运行时间大幅减少)。$ time ./v09MatMultElapsed Time Without I/O:
28918.17 ms.
&== V9 XLC compilerreal
0m29.00suser
0m28.93ssys
0m0.00s $ time ./v10MatMultElapsed Time Without I/O:
27978.91 ms.
&== V10.1 XLC compilerreal
0m28.10suser
0m28.03ssys
0m0.00s $ time ./v11MatMultElapsed Time Without I/O:
9162.79 ms.
&== V11.1 XLC compilerreal
0m9.20suser
0m9.17ssys
使用的编译命令: xlc -qnostrict -qhot=simd
-qarch=pwr6 -qtune=pwr6 -o [v09|v10|v11]MatMult
./matMult.c
值得注意的是,以上的结果是从普通的POWER6机器上获得的,该机器的配置参数如下:System Model: IBM,7998-61XMachine Serial Number: (deleted)Processor Type:
PowerPC_POWER6Processor Implementation
Mode: POWER 6Processor Version: PV_6Number Of Processors: 4Processor Clock Speed: 4005
MHzCPU Type: 64-bitKernel Type: 64-bitMemory Size: 15744 MBGood Memory Size: 15744 MBPlatform Firmware level:
EA320_030Firmware Version:
IBM,EA320_030 如果您想使用专业的性能测试机器来验证以上结论,请点击以访问IBM
沙盒测试演示(Sandbox
270003XAW2
2.039 vistas
,不算炎热的一天。然而我却控制不住自己内心的悸动,毕竟是第一次参与如此大型的customer activity,前期的准备工作非常充分,从video demo,演示的中文文稿,幻灯片,live demo,客户调研,如今,大战即将一触即发,深吸一口气,进入了龙之梦丽晶大酒店。- 8:00: 本以为算是很早到的,但是俨然场内人声鼎沸的气氛已不容许我再慢条斯理的欣赏了,门口签到处签到,注册,领取工作证,赶快奔向内场,找了一圈,偌大的会场左边, “XL Compiler(IBM Rational XL编译器,发布基于POWER系统的AIX及Linux平台下的XL C/C++ 和XL Fortran等系列编译器) - 让您的POWER更给力”的大型海报令我分外亲切,从logo,标语到设计凝结了整个工作团队的心血。开电脑,放demo,尝试演示,准备工作一切就绪。- 8:30: 团队工作人员基本到齐,大家有条不紊的进行着进一步的准备工作,此时,客户已经纷至沓来,在各个展台前或流连忘返,或游走于其间,我们的第一个客户来自于深发展,他对于POWER系列非常感兴趣,交流了下使用POWPC的经验,以及platform,editor直至compiler。此时我们展台前的客户还不算太多,因此有时间和客户进行深层次,长时间的沟通。- 9:00: Innovate 2011正式开幕,在主会场致完开幕词之后,主题演讲也正式拉开序幕。另外,除了主会场的主题演讲之外,每个分会场也安排了相关主题专家的演讲,针对四个不同主题也开辟了专家咨询咖啡区,随时开放答疑,让我们与客户之间的交流更加顺畅。除此之外,担心IT解决方案风险的客户还可以从现场的解决方案的全线展示区中获得成功实践者的经验,加速企业自身的方案实施进程,同样,于各个展台前和工作人员进行交流也是非常好的经验分享方式。由于各大session的火热展开,客户纷纷进入会场参与其中,我们也有了“忙里偷闲”的时刻,部分工作人员主动来到其他展台前与各位owner交流各自主打的产品,demo,客户群,目前工作状态等等。比如developerworks展台,巨大的标幅深入人心,另有趣味答题环节,吸引客户前来参与互动,作为一位IBMer,自己对于developerworks的历史,发展却着实不甚熟悉,通过关注该环节,确确实实的获得了很多knowledge。又或者坐落于我们隔壁的RQM(IBM Rational Quality Manager, 优秀的协作型质量管理解决方案)展台,趁着有机会,我们也现场操作了一把,平时只知其名的产品,如今能够身临其境的去使用,帮助更好地理解我们Rational的产品。-11:00: 主会场上午的session结束了,大量的客户再次鱼贯进入各个展台,我们的工作也陷入到疯狂之中,面对七嘴八舌的用户,除了不同的问题,需求,我们必须要一一耐心作答的同时,还要做好客户调研,包括收集客户的开发方向,是否POWER用户,使用AIX/Linux平台,是否使用IBM XL编译器,客户的pain,对于效率的要求,关注的方向等等。整个展台忙做一团,却又乐在其中,与客户思想碰撞的火花,谈笑风生的经验交流,彼此都深深融入其中。-12:30: 大多数客户都去用餐了,我们展台的工作人员又获得了喘息之机,趁此机会,赶紧轮班去用午饭,顺便参观了下整个会场以及下午各个主题演讲的“排片表”。快速的消耗了些肯德基和饮料,准备下午再战!其中有个小花絮,我们误入了嘉宾休息室,原本以为是老板们休憩的豪华场所,但没想到大多数的都在准备下午的主题演讲,另外针对老外的英语主题演讲,翻译者们(大多数是敬业的经理们)也陪同一起做着紧张的准备工作。在执着的瞅了一会之后,我们也回到了属于自己的岗位上。- 13:00: 较之上午,客户群体换了一批,量比起上午来也稍微少了点,不过繁忙依旧。客户针对我们的编译器功能与性能有了进一步的交流,甚至一些资深的用户和我们探讨起编译器的优化技术和新一代语言标准的发布。- 14:00: 一位重量级的人物光临我们展台,他就是IBM的资深编译器专家,Kevin Stoodley(IBM Fellow: CTO Enterprise Modernization Tools, Compilers and Security)。他也像一位普通的customer那样对于我们的showcase进行了各个方面的交流和分享,在肯定我们工作的同时,他也给出了许多专业性意见关于如何改进今后Innovate我们的demo,如何更好地show出XL编译器在POWER的优势,比如使用一个大型的application去测试我们的性能,而非benchmark的简单叠加,又或者拿同期的其他主流编译器,比如GCC等做各类不同情况下的性能对比,从中,我们获益匪浅。- 15:00: 客户再次进入各个主会场参与主题报告,我们工作人员也有的放矢的进行轮岗,有时间的同事也参与到各个主题报告中去。非常红火的有介绍RTC(Rational Team Concert, 一款强大的团队协作,任务整合工具)的session(基于Jazz平台的协作生命周期管理演示),Steve Hikida(IBM Director: Rational Security, Automation, and Cloud Development)的application security(树立在应用程序的设计阶段确保其安全性的策略),另外当然不能错过的还有Kevin Stoodley的企业级应用讲座(企业现代化:突破性地提升多平台应用设计和开发的经济效益),边听着报告,边思考着演讲嘉宾与场下观众们的互动,时间如白驹过隙。- 16:30: 客户与嘉宾们逐渐离开,我们也在进行着收拾展台的工作。一天忙碌的工作即将落下帷幕,手捧满满的客户调研报告,望着XL Compiler的大幅海报,一切都是很有价值的!- 17:00: 包括工作人员在内的大多数人员都准备离开了,看着较为空旷的展台区,我们留下了今年最甜美的回忆。Software Everyware,明年我们再见!
270003XQKW
9.898 vistas
在编写应用程序时,我们经常要使用到字符串。C++标准库中的&string&和&sstream&为我们操作字符串提供了很多的方便,例如:对象封装、安全和自动的类型转换、直接拼接、不必担心越界等等。但今天我们并不想长篇累牍得去介绍这几个标准库提供的功能,而是分享一下stringstream.str()的一个有趣的现象。我们先来看一个例子:
#include &string&
#include &sstream&
#include &iostream&
int main()
stringstream ss(&&);
stringstream t_ss(&abcdefghijklmnopqrstuvwxyz&);
string str1(ss.str());
const char* cstr1 = str1.c_str();
const char* cstr2 = ss.str().c_str();
const char* cstr3 = ss.str().c_str();
const char* cstr4 = ss.str().c_str();
const char* t_cstr = t_ss.str().c_str();
cout && &------ The results ----------& && endl
&& &cstr1:\t& && cstr1 && endl
&& &cstr2:\t& && cstr2 && endl
&& &cstr3:\t& && cstr3 && endl
&& &cstr4:\t& && cstr4 && endl
&& &t_cstr:\t& && t_cstr && endl
&& &-----------------------------&
在看这段代码的输出结果之前,先问大家一个问题,这里cstr1、cstr2、cstr3和cstr4 打印出来结果是一样的么?(相信读者心里会想:结果肯定不一样的嘛,否则不用在这里“故弄玄虚”了。哈哈)
接下来,我们来看一下这段代码的输出结果:
------ The results ----------
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
t_cstr: abcdefghijklmnopqrstuvwxyz
-----------------------------
这里,我们惊奇地发现cstr3和cstr4竟然不是ss所表示的数字字符串,而是t_ss所表示的字母字符串,这也太诡异了吧,但我们相信“真相只有一个”。下面我们通过再加几行代码来看看,为什么会出现这个“诡异”的现象。
#include &string&
#include &sstream&
#include &iostream&
#define PRINT_CSTR(no) printf(&cstr& #no & addr:\t%p\n&,cstr##no)
#define PRINT_T_CSTR(no) printf(&t_cstr& #no & addr:\t%p\n&,t_cstr##no)
int main()
stringstream ss(&&);
stringstream t_ss(&abcdefghijklmnopqrstuvwxyz&);
string str1(ss.str());
const char* cstr1 = str1.c_str();
const char* cstr2 = ss.str().c_str();
const char* cstr3 = ss.str().c_str();
const char* cstr4 = ss.str().c_str();
const char* t_cstr = t_ss.str().c_str();
cout && &------ The results ----------& && endl
&& &cstr1:\t& && cstr1 && endl
&& &cstr2:\t& && cstr2 && endl
&& &cstr3:\t& && cstr3 && endl
&& &cstr4:\t& && cstr4 && endl
&& &t_cstr:\t& && t_cstr && endl
&& &-----------------------------&
printf(&\n------ Char pointers ----------\n&);
PRINT_CSTR(1);
PRINT_CSTR(2);
PRINT_CSTR(3);
PRINT_CSTR(4);
PRINT_T_CSTR();
在上述代码中,我们把那几个字符串对应的地址打印出来,其输出结果为:
------ The results ----------
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
t_cstr: abcdefghijklmnopqrstuvwxyz
-----------------------------
------ Char pointers ----------
cstr1 addr:
cstr2 addr:
cstr3 addr:
cstr4 addr:
t_cstr addr:
从上面的输出,我们发现cstr3和cstr4字串符的地址跟t_cstr是一样,因此,cstr3、cstr4和t_cstr的打印结果是一样的。按照我们通常的理解,当第17-19行调用ss.str()时,将会产生三个string对象,其对应的字符串也将会是不同的地址。
而打印的结果告诉我们,真实情况不是这样的。其实,streamstring在调用str()时,会返回临时的string对象。而因为是临时的对象,所以它在整个表达式结束后将会被析构。由于紧接着调用的c_str()函数将得到的是这些临时string对象对应的C string,而它们在这个表达式结束后是不被引用的,进而这块内存将被回收而可能被别的内容所覆盖,因此我们将无法得到我们想要的结果。虽然有些情况下,这块内存并没有被别的内容所覆盖,于是我们仍然能够读到我们期望的字符串,(这点在这个例子中,可以通过将第20行删除来体现)。但我们要强调的是,这种行为的正确性将是不被保证的。
通过上述分析,我们将代码修改如下:
#include &string&
#include &sstream&
#include &iostream&
#define PRINT_CSTR(no) printf(&cstr& #no & addr:\t%p\n&,cstr##no)
#define PRINT_T_CSTR(no) printf(&t_cstr& #no & addr:\t%p\n&,t_cstr##no)
int main()
stringstream ss(&&);
stringstream t_ss(&abcdefghijklmnopqrstuvwxyz&);
string str1(ss.str());
const char* cstr1 = str1.c_str();
const string& str2 = ss.str();
const char* cstr2 = str2.c_str();
const string& str3 = ss.str();
const char* cstr3 = str3.c_str();
const string& str4 = ss.str();
const char* cstr4 = str4.c_str();
const char* t_cstr = t_ss.str().c_str();
cout && &------ The results ----------& && endl
&& &cstr1:\t& && cstr1 && endl
&& &cstr2:\t& && cstr2 && endl
&& &cstr3:\t& && cstr3 && endl
&& &cstr4:\t& && cstr4 && endl
&& &t_cstr:\t& && t_cstr && endl
&& &-----------------------------&
printf(&\n------ Char pointers ----------\n&);
PRINT_CSTR(1);
PRINT_CSTR(2);
PRINT_CSTR(3);
PRINT_CSTR(4);
PRINT_T_CSTR();
现在我们将获得我们所期望的输出结果了:
------ The results ----------
t_cstr: abcdefghijklmnopqrstuvwxyz
-----------------------------
------ Char pointers ----------
cstr1 addr:
cstr2 addr:
cstr3 addr:
cstr4 addr:
t_cstr addr:
现在我们知道stringstream.str()方法将返回一个临时的string对象,而它的生命周期将在本表达式结束后完结。当我们需要对这个string对象进行进一步操作(例如获得对应的C string)时,我们需要注意这个可能会导致非预期结果的“陷阱”。:)
最后,我们想强调一下:由于临时对象占用内存空间被重新使用的不确定性,这个陷阱不一定会明显暴露出来。但不暴露出来不代表行为的正确性,为了避免“诡异”问题的发生,请尽量采用能保证正确的写法。
另外,本文以上所有输出结果的运行环境是: Red Hat Enterprise Linux Server release 5.8 (Tikanga) Linux 2.6.18-308.el5 ppc64 GNU/Linux gcc version 4.1.2
(Red Hat 4.1.2-52)
1. /questions/1374468/c-stringstream-string-and-char-conversion-confusion
270003XQKW
8.685 vistas
在编写C语言的应用程序时,为了获取或者打印一些跟时间有关的信息,我们经常会使用到C语言自带的一些时间函数,诸如:time、localtime、ctime、mktime和asctime等。但你可能没有注意到这里面含有一些有趣的现象,先来看一个例子:
1 #include &stdio.h&
2 #include &time.h&
4 int main ()
time_t time_1, time_2;
struct tm *tm_1, *tm_2, *tm_3;
struct tm tm_4, tm_5; 10 11
printf(&-------------------- PART I -------------------\n&); 12 13
time_1 = time(NULL); 14
sleep(3); 15
time_2 = time(NULL); 16
printf(&time1:%d time2:%d\n&,time_1,time_2); 17 18
tm_1 = (struct tm*)localtime(&time_1); 19
tm_2 = (struct tm*)localtime(&time_2); 20
tm_3 = (struct tm*)localtime(&time_1); 21 22
printf(&tm_1 ptr:%p tm_2 ptr:%p tm_3 ptr:%p\n&,tm_1,tm_2,tm_3); 23
printf(&asctime(tm_1):%s&,asctime(tm_1)); 24
printf(&asctime(tm_2):%s&,asctime(tm_2)); 25
printf(&asctime(tm_3):%s&,asctime(tm_3)); 26 }
在看这段代码的输出结果之前,先问大家两个问题:
(1) 第22行,struct tm结构体 tm_1、tm_2和tm_3的值有什么关系?
(2) 第23-26行的输出结果中,tm_2的时间真的比tm_1晚3秒吗?
接下来,我们来看一下这段代码的输出结果:-------------------- PART I -------------------time1: time2:tm_1 ptr:0xfec6f48 tm_2 ptr:0xfec6f48 tm_3 ptr:0xfec6f48asctime(tm_1):Thu Jun 21 01:32:54 2012asctime(tm_2):Thu Jun 21 01:32:54 2012asctime(tm_3):Thu Jun 21 01:32:54 2012
这里的打印结果是否跟你前面预想的一样呢?没错,第22行中的tm_1、tm_2和tm_3其实指向的是同一个地址。在localtime函数的实现中,采用了一个静态内部struct tm结构体来存储对应的时间信息。每次对localtime函数的调用,都将会修改内部这个struct tm结构体,也就是说,这个结构体将只会保存最新的调用结果。因此,localtime每次返回的struct tm结构体也将是同一个,即指向的地址是同一个。这也就意味着,后续第23行到第25行对asctime的调用中,实际上传入的都是同一个结构体(指向同一个地址的指针),结果它们打出来的时间一样也就不足为奇了。
我们再来看以下这段代码:
1 #include &stdio.h&
2 #include &time.h&
4 int main ()
time_t time_1, time_2;
struct tm *tm_1, *tm_2, *tm_3;
struct tm tm_4, tm_5; 10 11
printf(&-------------------- PART I -------------------\n&); 12 13
time_1 = time(NULL); 14
sleep(3); 15
time_2 = time(NULL); 16
printf(&time1:%d time2:%d\n&,time_1,time_2); 17 18
tm_1 = (struct tm*)localtime(&time_1); 19
tm_2 = (struct tm*)localtime(&time_2); 20
tm_3 = (struct tm*)localtime(&time_1); 21 22
printf(&tm_1 ptr:%p tm_2 ptr:%p tm_3 ptr:%p\n&,tm_1,tm_2,tm_3); 23
printf(&asctime(tm_1):%s&,asctime(tm_1)); 24
printf(&asctime(tm_2):%s&,asctime(tm_2)); 25
printf(&asctime(tm_3):%s&,asctime(tm_3)); 26
printf(&-------------------- PART II -------------------\n&); 29 30
time_1 = time(NULL); 31
sleep(3); 32
time_2 = time(NULL); 33
printf(&time1:%d time2:%d\n&,time_1,time_2); 34 35
tm_4 = *((struct tm*)localtime(&time_1)); 36
tm_5 = *((struct tm*)localtime(&time_2)); 37 38
printf(&tm_4 ptr:%p tm_5 ptr:%p\n&,&tm_4,&tm_5); 39
printf(&tm_4 sec:%d tm_5 sec:%d\n&,tm_4.tm_sec,tm_5.tm_sec); 40 41
printf(&asctime(&tm_4):%sasctime(&tm_5):%s&,asctime(&tm_4),asctime(&tm_5)); 42
printf(&asctime(&tm_4) ptr:%p asctime(&tm_5) ptr:%p\n&,asctime(&tm_4),asctime(&tm_5)); 43 44
printf(&asctime(&tm_4):%s&,asctime(&tm_4)); 45
printf(&asctime(&tm_5):%s&,asctime(&tm_5));
在第28行之前跟上面的示例代码是一样,这里就不再冗述,我们主要来看剩余部分。既然在前面我们已经知道了localtime返回的是同一个内部静态结构的地址,那么我们不禁想到可以将它赋值给本地结构体,这样前面对localtime函数的返回值可以得到保存,不会被后面的调用所覆盖,如第35和36行所示。那么,我们不禁想问:第41行打印出来的结构体tm_4和tm_5对应的时间结果跟第44-45行打印出来的一样么?
我们来看一下PART II的输出结果:-------------------- PART II -------------------time1: time2:tm_4 ptr:0xffe82dd8 tm_5 ptr:0xffe82e08tm_4 sec:57 tm_5 sec:0asctime(&tm_4):Thu Jun 21 01:33:00 2012asctime(&tm_5):Thu Jun 21 01:33:00 2012asctime(&tm_4) ptr:0xfec59dc asctime(&tm_5) ptr:0xfec59dcasctime(&tm_4):Thu Jun 21 01:32:57 2012asctime(&tm_5):Thu Jun 21 01:33:00 2012
输出结果跟你的预期一样么?我们惊奇地发现,第41行打印的结果中,tm_4和tm_5的时间字符串是一样的。但我们通过打印出tm_4和tm_5结构体的地址,以及对应的秒数(tm.sec),都可以让我们确信这次tm_4和tm_5是两个不同的时间结构体。问题其实出在asctime函数中,通过打印asctime调用tm_4和tm_5结构体后返回的指针地址,我们发现这两个地址是一样的。从asctime函数的行为,我们不难联想到,其实它的内部实现跟localtime类似,它也使用了一个内部静态字符数组来保存转换好的时间字符串。每次对asctime的调用,都将修改这个字符串,而函数每次都将返回同一个地址,即内部静态字符数组的地址。
下面我们来分析一下第41行的行为:
1) 调用asctime(&tm_4),按照tm_4的信息更新内部静态字符数组,返回字符数组的地址;
2) 调用asctime(&tm_5),按照tm_5的信息更新内部静态字符数组,返回字符数组的地址。在这一步中,新的tm_5的信息将会覆盖掉原来tm_4的那些信息。
3) 打印第一个参数指向地址的字符串,即该内部静态字符数组。此时这个字符串已经被更新为tm_5的信息了,因此,将打印tm_5对应的时间信息。
4) 打印第二个参数指向地址的字符串,即tm_5对应的时间信息。
而在第44行中,我们在调用asctime函数后,随即将信息打印出来,此时则为tm_4的时间信息。同理,跟我们对localtime函数的操作类似,我们也可以通过本地字符数组来保存asctime函数的调用结果,从而避免结果被后续的调用所覆盖。
根据POSIX标准,时间函数asctime()、ctime()、gmtime()和localtime()函数都将返回内部静态对象,要么是struct tm结构体,要么是字符数组。因此,在对这些函数的调用时,我们需要额外的小心,如果不需要保存其调用结果,我们可以及时地打印,如果需要保存其调用结果,可以采用本地结构来临时存放。
参考文献: 1. asctime函数说明 http://linux.die.net/man/3/asctime2. localtime函数说明 http://linux.die.net/man/3/localtime
2.329 vistas
当您在运行程序时,是否关心过程序的安全性呢?XL
C/C++V11.1/FortranV13.1编译器为您提供了一个栈保护的特性。这个特性并非是一个保护栈帧,或是禁止在栈上进行写操作的系统。这里的栈保护是一种能够检测栈损毁、重写等问题,并进而采取措施的防御机制。无论栈是怎样损毁了,编程错误也好,系统攻击也好,栈保护机制总能确保及时地结束程序进行。 编译器有用个新选项来支持栈保护:-qstackprotect
-qinfo=stp. -qstackprotect,
这个选项可以设定栈保护的工作范围。通过-qstackprotect=all,可以告诉编译器要保护包含主函数在内的所有函数。通过-qstackprotect=size=N,允许对特定字节以及更大字节数的易受攻击对象进行保护。
使用这些选项会带来一些疑问,比如:什么是易受攻击的对象?可以这么讲,易受攻击的对象,指的是那些可能访问超出它内存分配以外数据的对象。对Fortran来说,易受攻击对象就包括了形式参数、具有可分配属性的本地变量、具有指针属性的本地变量,以及声明为数组的本地变量等。
另一个问题就是:为什么不总是保护所有的函数,却偏偏设计了这种保护特定范围的函数的机制呢?简单说,这是出于性能考虑。栈保护的开销完全依赖于程序的编写方式。举个例子,假设一个程序使用了大量的getters和setters。对于每个被保护的函数,编译器将插入额外的代码来构建栈帧。如下图所示,这些代码,即Canary
Word,会插到栈上的返回地址和形式参数或本地变量之间。当然,在函数调用返回时,编译器会在紧接着函数返回代码的地方插入额外的一些代码,用于函数返回时验证Canary
Word的值是否正确(译:验证出错误即发生了程序错误或者受到攻击)。额外开销适当的话,应该使用-qstackprotect=size=N这一子选项来保护你的软件。 /* C */
void blank ( char* cvar )
*cvar = ' ';
subroutine blank ( cvar )
character(4) :: cvar(:)
cvar = ' '
end subroutine
函数blank的栈帧结构如下所示: --------------------------
--------------------------
Return Address
--------------------------
Stack Pointer
--------------------------
Canary Word
--------------------------
--------------------------
--------------------------
另一个命令行选项是-qinfo=stp,使用这个选项,编译器将以警告信息的形式告知哪些函数没有受到栈保护。通过使用这个选项,你可以对-qstackprotect=size=N进行微调,直到找到最适合你程序的N值。现在我们将前面讲到的汇总到下面这个例子: ! Fortran
SUBROUTINE set_broken (this, key)
CHARACTER(*), INTENT(in)
CLASS(keyboard)
this%number_broken = this%number_broken + 1
this%broken_keys(this%number_broken) = key
END SUBROUTINE set_broken &
FUNCTION get_broken_keys (this)
CHARACTER(10)
:: get_broken_keys(2)
CLASS(keyboard), INTENT(in) :: this
get_broken_keys = this%broken_keys
END FUNCTION get_broken_keys
void set_broken (char key)
++keyboard.number_broken;
keyboard.broken_keys[keyboard.number_broken] =
char* get_broken_keys ()
char local_array[20];
return keyboard.broken_keys;
这里我们有两个函数:get_broken_keys,它有一个20字节的数组;set_broken,它没有包含易受攻击的对象。如果我们不想保护它们中的任意一个,那合适的命令行选项应该是-qstackprotect=size=20
-qinfo=stp,这时候将产生下列输出:
(W) WARNING: set_broken is not protected against stack smashing.
(W) WARNING: get_broken_keys is not protected against stack smashing.
可以看到,栈保护对于编程人员来说非常透明,且易于在性能与安全性之间取得平衡。而通过栈保护,软件用户也将最终得到一个远离恶意攻击和编程错误的产品。
3.017 vistas
本演示阐述了如何通过XL编译器支持的自动向量化功能来使用MASS高性能数学库。演示中的各个示例来自developerWorks(开发者论坛)中的一篇文章()。有关MASS库,自动向量化和Fortran/C源代码的详细信息请参考上述文章。
2.434 vistas
结果明显是错误的,但问题在哪里?眼尖的读者可能已经看出来了,该程序包含了一个竞态状态(race condition)。多个线程可以并发的写共享变量&sum&,这可能会重写掉之前已经写入的部分值。
为了消除这种竞态状态,我们可以用临界区(critical section)在写&sum&这个变量时进行保护。UPC是通过使用&锁(lock)&变量来实现的,如:
upc_forall ( i=0;i&N;i++;&A[i] )
upc_lock ( lock );
sum = sum + A[i];
upc_unlock ( lock );
修改后的程序就能输出正确的结果了。但这种办法的背后的原理是什么呢?锁的使用有效的串行了upc_forall的各次循环,这牺牲了并行执行带来的性能。为了能确认这个理论,我们做了个测试,测量了上面的upc_forall循环计算数组元素的总和要用多久。我们的实验环境是AIX5.3,Power5以及32个线程。
从图1的结果来看,我们可以得出结论:upc_forall的执行时间并没有因为线程的增加而得到明显改进。这是我们所期望的结果,因为在循环中使用锁会阻止循环的并发执行。
270003XAW2
2.380 vistas
规约的过程即是通过合并一个向量(或数组)中的所有元素,从而产生单个聚合元素的过程。他被广泛应用在科学计算之中。比如,我们需要计算两个n维向量x,y的向量积,如下所示:
这次计算需要n次乘法以及n-1次加法,其中n次乘法是互相独立的,因此他们可以并行执行,当计算完毕之后就可将各个乘法结果全部加起来得到最终结果。
考虑到规约操作对于科学算法的重要性,许多并行语言也提供了对于用户自定义规约的支持。比如,OpenMp提供了用户规约语句,可以被使用在OMP并行块之中。在下面的例子当中,规约语句表明了&sum&为一个规约变量:
在以上的代码片段中,每个线程独立完成了部分加法进而得到了最终结果。在并行循环的最后,部分和被合并为结果值。在本篇文章中我们会基于UPC,针对全局和规约的实现进行探索,尝试着发现更加高效和可扩展的实现。Unified Parallel C (UPC) 是C语言的一种扩展形式,允许用户在他们的代码之中表达并行。UPC语言支持PGAS(Partition Global Address Space - 分布式全局地址空间)编程模型。PGAS语言,比如UPC,逐渐地被视作为一个便利的方式来增强程序员在大型机上对于HPC(High-Performance Computing - 高性能计算)应用程序的生产率。
一个UPC程序由固定数量(在程序启动时设定)的线程(THREAD)执行。通常来说一个程序语句可以被所有线程并行执行,为了促进线程之间的分布与协调工作,UPC还提供了大量的语言特性,你可以访问以下的链接找到UPC教程: . 让我们来考虑下如何用UPC写一个简单的和规约程序:
在第5-6行,我们定义了一个共享数组&A&和一个共享变量&sum&。在第10-12行,我们将A中所有元素初始化为1。在第15-17行,我们尝试着完成规约操作,将A中元素值累加到共享变量sum中去。这个程序正确吗? 一个可能的程序输出是:
想知道最终结果么?敬请期待!
2.155 vistas
在Power系统的企业现代化沙盒中,可以直接体验IBM编译器产品,无需安装。Power系统上的企业现代化沙盒是一个云产品,它提供了一个专用、强大、互联的系统环境。IBM power系统上已经为您预装了企业现代化沙盒,用户可以直接使用。企业现代化沙盒中每一个客户解决方案都包含简单可行的用户示例,示例描述了在Power系统上用户如何最优化应用程序、团队及硬件设施的价值。
1.954 vistas
原文地址:
TANSTAAFL=&There ain't no such thing as a free lunch&.(译:世上没有免费的午餐)Robert Heinlein 在他的 &The Moon is a Harsh Mistress&(译:月亮是个苛刻的主妇)曾这么地给我们忠告。
有位杰出的作者引用上面这句话,来说明摩尔定律带来的单芯片时钟周期,每18个月性能免费提升的终结。这预示着,在将来,性能的提升已经不再是简单的,坐着等着时钟的加速了。它需要你把并行的思想嵌入到你的代码中,让你的代码能够充分的发挥不断出现的多核系统的性能。
这个需要一个全新的思维模式,彻头彻尾的。
大家好,我的名字叫做 Michael Wong. 我是IBM OpenMP和C++标准的代表。 我和我的同事们将会给这个博客带来一些关于并行和多核计算方面的行业核心趋势。我们把我们自己定位为一个实现者, 技术汇总和各种各样的标准委员会以及企业的代表。
事实上,随着各种各样的标准,规格,制造商们开始从编程模式,应用程序和硬件上支持多核技术,并行和多核计算的黄金时期已经来临了。比较近的例子有,Cell,OpenMP 3.0, 新的Java内存模型, UPC和co-array Fortran, C++0x 并行技术, Cilk, 事务内存(TM),自动化并行以及各种各样的专利和研究项目。
毫无疑问,多核技术已经在系统和处理器设计上面发挥了重大的作用。但它同时也是隐含在软件整个开发周期中,需要考虑的问题。
因此呢,平时有空多光顾这个博客,来了解多核的奥秘。
626 vistas
z/OS&V2.2&XL&C/C++编译器作为z/OS&v2.2的一个可选付费功能,在2015年9月30日正式发布。
&&&&&&& 这个编译器版本提供了对新的的支持,实现了参数ARCH(11)和TUNE(11),以利用新指令来更好地优化生成的代码。编译器同时支持z13向量扩展部件提供的单指令多数据 (SIMD)指令和相应的向量编程语言扩展,以及IBM&MASS(Mathematical&Acceleration&Subsystem数学加速子系统)和ATLAS(Automatically&Tuned&Linear&Algebra&Software自动调整线性代数软件)库。MASS库用于对基本数学函数的加速执行,是可以替代z/OS&XL&C/C++&runtime标准数学库的高性能库。ATLAS库设计提供对 BLAS(Basic&Linear&Algebra&Subprograms)和LAPACK(Linear&Algebra&PACKage)函数的线性代数函数支持,后者通常用于业务分析和优化的解决方案。这两个库提供强大的构架,用于新的业务分析应用的开发,从其它平台向z/OS迁移数学密集型的应用,并且帮助在zEC12,&zBC12和z13处理器上加速业务分析应用。z/OS&V2.2&dbx同样支持在z/OS&UNIX上调试使用向量变量和SIMD指令的C/C++程序。
&&&&&& 此外,z/OS&V2.2&XL&C/C++增强了易用性和性能:
-&&&支持内嵌汇编语句,使用户可以在XL&C和XL&C++代码中插入汇编语句。该功能不再需要Metal&C编译,使用户能够在C和C++对象中很容易地使用特定指令。
-&&&运行架构块(runtime&architecture&block)使用户能够在一个源文件中利用到多个不同的硬件架构,并指定系统在运行时选择合适的路径运行。这个功能使得一个可执行文件可以对不同的硬件架构有不同的优化路径,以帮助提升性能。
&&&&&& 除此之外,z/OS&V2.2&XL&C/C++还包括:
-&&&代码的自动转换,以利用向量部件,更有效地开发硬件特性,以及并行化代码,来提高应用性能。
-&&&支持dbgld工具,用于收集源代码并放入模块级的调试文件,使用户可以察看或使用不可执行的代码。
-&&&加强的Metal&C设计,如果需要可以允许更大的保留DSA域,使得从非标准连接(nonstandard&linkage)迁移更容易,并提供更多灵活性。
&&&&&&& 与zEC12上的z/OS&V2R1&XL&C/C++编译器相比,z/OS&V2R2&XL&C/C++编译器在z13上提供了最大24%的吞吐率提升。这个巨大的提升来源于更强大的硬件和编译器优化的进一步提升。以上性能提升基于IBM实验室的内部评测。特定应用的性能结果可能有变化,取决于源代码,编译器选项和其它因素。
&&&&&&& 更多信息可以访问的标签2.2。
translated by Annita Zhang
5.210 vistas
原文地址: C++编程语言的新标准C++11(定稿前的名称是C++0x) 已经定稿并且公布出来了。C++11将替代C++ 2003(修改了C++ 1998中的一些问题),其官方编号为:ISO/IEC 。 IBM的xlC(C++)编译器已经从2008年发布的V10.1开始支持C++11的许多特性。我们目前的版本是AIX和Linux的V11.1,z/OS上的V1R12。其他多数编译器也有类似的规划,将众多的特性分阶段的在多个版本中实现。 下面列出的是不同XL C/C++编译器版本所支持的C++11的特性: 2008年中期发布的AIX和Linux平台的XL C/C++ V10.1所支持的C++11的特性:* -qlanglvl=extended0x (打开C++11特性,类似gcc 的-std=c++11)* long long* sync C99 preprocessor* Empty macro arguments* Variadic macros * Trailing comma in enum definition* Concatenation of mixed-width string literal除此之外,该版本编译器已经通过了 的测试。 2010年中期发布的AIX和Linux平台的XL C/C++ V10.1所支持的C++11的特性(包含上面全部):* Variadic template* Auto* Decltype* Namespace association* Delegating constructor* Static assert除此之外,该版本编译器已经通过了 的测试。 z/OS平台的XL C/C++ V1R11支持的C++11的特性:* Extern template* Extended friend* -qwarn0x z/OS平台的XL C/C++ V1R12支持的C++11的特性:* Long longC99 preprocessor* Auto* Decltype* Variadic template* Namespace association* Delegating constructor* Static assert
我们计划继续推动并发布全面支持C++11的新版本编译器如果您想了解更多有关C++11,请参考Bjarne的
4.156 vistas
原文地址:
IBM XL 编译器可以和很多工具一起配合使用。 比如,一些工具可以提高开发阶段的效率(IBM 程序调制器,RDp), 一些工具可以帮助研究架构特性(编译器报告), 另外还有些工具可以帮助使用硬件资源。IBM 并行环境程序产品(PE) 是一个可以运行在AIX和Linux平台上的分布式内存消息发送系统。它是一个独立的IBM产品。如果您想了解到它的详细信息,请参考以下网页:。PE是用来开发和执行并行的Fortran, C, 和C++程序的。 PE支持两种基本的并行程序模式-SPMD和MPMD。在SPMD (单程序多数据)模式下,多个并行任务运行相同的程序,但是处理不同的数据集。在MPMD(多程序多数据)模式下,每一个任务可能运行不同的程序。 下面我们来谈谈XL 编译器和PE是怎么相互协作利用并行运算环境进行开发的。PE提供了一套命令帮助用户编译运行于并行环境的程序。这些命令实际上最终调用了XL编译器,只是使用了特殊的选项并连接了特定的库(分割管理器和消息传递接口库)来支持并行运行环境。这些命令的命名都是以”mp”开头。比如, mpcc_r是用于C程序的,mpxlf90_r是用于Fortran程序,mpCC_r是用于C++程序的。在执行方面,PE提供了poe命令,它可以调用并行操作环境(POE)来实现远程处理节点上的程序加载和执行。下面我们通过一个简单的例子来说明XL 编译器和PE是怎么一起工作的。在这个例子中,一个C程序(main.c) 调用一个fortran的过程(arr_cal.f90)来做运算,并且将结果打印在main函数里。main.c#include &stdio.h&void initialize_arr(float *, int n);float summation(float *, int n);void main(){
int N=500;
float arr[N],
initialize_arr(arr, N);
tot = (arr, N);
printf(&tot = %f\n&, tot); }arr_cal.f90subroutine initialize_arr(arr, n) bind(c)
use, intrinsic :: iso_c_binding
real(kind=c_float) :: arr(n)
integer(kind=c_int), value :: n
call random_number(arr) end subroutine function summation(arr, n) result(tot) bind(c)
use, intrinsic :: iso_c_binding
integer(kind=c_int), value :: n
real(kind=c_float) :: arr(n), tot
tot = sum(arr) end function在AIX中,使用以下命令编译,连接程序。 $ mpxlf90_r -c arr_cal.f90$ mpcc_r &c main.c$ mpxlf90_r arr_cal.o main.o &o test1上面产生的可执行程序可以通过poe命令运行于一个机器集群上。在此之前,我们必须创建一个主机文件来指定程序将运行于哪些主机上。另外,远程主机上必须创建相同的路径(与本地机器的当前绝对路径一致)。host.list! comments: have the following hosts available 以下是在上述主机上运行程序的命令: $ mcp ./test1 -procs 4 -hfile host.list$ poe ./test1 -procs 4 -hfile host.listtot = 248.259613tot = 248.259613tot = 248.259613tot = 248.259613选项-proc是用来指定创建任务数的。在这个例子中,我们将创建四个任务来运行同一个程序(test1),这些任务运行在host.list指定的主机上。mcp命令负责拷贝可执行程序到远程主机上。选项-labelio用任务序号来指定并行任务的输出。$ poe ./test1 -procs 4 -hfile host.list -labelio yes
2:tot = 248.259613
3:tot = 248.259613
1:tot = 248.259613
0:tot = 248.259613 这个简单程序的例子演示了XL编译器如何与PE协同工作。如果您需要开发一个基于分布环境的程序,PE是最重要的工具。PE还提供了并行程序调试器(PDB)用来帮助调试并行程序。在今天的博客里,我们简要描述了PE产品和如何通过使用XL编译器来开发基于并行环境的程序。当然,真实世界里的并行程序远比今天的这个的例子复杂和有用。有的并行应用程序首先把问题解构到比较小的规模,分派到不同的主机并开始计算。运算完成以后,应用程序再把结果数据收集回来进行处理,得到最终结果。此外,我们还演示了使用poe命令在远程主机上运行并行程序。
1.995 vistas
我们最近又发布了两款Linux编译器的最新PTF(Program Temporary Fix).这两款V9.0/11.1的最新PTF能提供对Red Hat Enterprise Linux 6.0的Runtime兼容性支持。这意味着您可以使用它们在RHEL 5.x的系统上进行编译,生成的应用程序既可以在RHEL5.x上运行,也可以被拷贝到RHEL6.0系统上运行。如果您正在使用V9.0和V11.1又想让应用程序能兼容最新的RHEL6,您只需下载并使用这两款最新的PTF,而无需升级现有Build机器的操作系统。
2.268 vistas
在Red Hat 近日刚刚发布最新RHEL6.2之后,IBM XL编译团队也在本月发布了两款最新的编译器PTF(Program Temporary Fix)来对其进行支持。February 2012 Update for XL C/C++ for Linux, V11.1 CompilerFebruary 2012 Update for XL C/C++ for Linux, V11.1 RuntimeFebruary 2012 Update for XL Fortran for Linux, V13.1 CompilerFebruary 2012 Update for XL Fortran for Linux, V13.1 Runtime如果您正在使用IBM最新的基于Power7的各种服务器,我们极力推荐您使用这两款最新版本的V11.1/13.1编译器,以获得更好的OS支持,性能及用户体验。
1.704 vistas
前不久,Novel发布了SUSE Linux Enterprise Seve
10的最新service pack SP4。Red Hat也发布了他们最新的Red Hat Enterprise Linux 6.1 和 Red Hat Enterprise Linux 5.7。我们很高兴的通知大家,XL目前最新版本的Linux编译器 (XL C/C++ V11.1 and XL Fortran V13.1) 已经在上个月及时发布了PTF(Program Temporary Fix),来支持这些最新的Linux版本。
October 2011 Update for XL C/C++ for Linux, V11.1 Compilerhttp://www-/support/docview.wss?uid=swgOctober 2011 Update for XL C/C++ for Linux, V11.1 Runtimehttp://www-/support/docview.wss?uid=swgOctober 2011 Update for XL Fortran for Linux, V13.1 Compiler:http://www-/support/docview.wss?uid=swgOctober 2011 Update for XL Fortran for Linux V13.1 Runtime:http://www-/support/docview.wss?uid=swg
如果您升级了上述Linux系统,也欢迎您下载并使用我们最新的编译器版本,以获得更好的兼容性支持。
2.197 vistas
我们最近又发布了两款Linux编译器的最新PTF(Program Temporary Fix).June 2011 Update for XL C/C++ for Linux, V10.1June 2011 Runtime for XL C/C++ for Linux, V10.1June 2011 Update for XL Fortran for Linux, V12.1June 2011 Runtime for XL Fortran for Linux, V12.1这两款V10.1/12.1的最新PTF能提供对Red Hat Enterprise Linux 6.0的Runtime兼容性支持。这意味着您可以使用它们在RHEL 5.x的系统上进行编译,生成的应用程序既可以在RHEL5.x上运行,也可以被拷贝到RHEL6.0系统上运行。如果您正在使用V10.1和V12.1又想让应用程序能兼容最新的RHEL6,您只需下载并使用这两款最新的PTF,而无需升级现有Build机器的操作系统。随着这两款PTF的发布,目前我们所有较老版本的Linux编译器产品都能够提供对RHEL6的Runtime兼容性支持。

我要回帖

更多关于 预付款能退吗 的文章

 

随机推荐